在软件开发中,我们经常会遇到需要根据对象的状态来改变其行为的情况。比如,一个文档可以处于"草稿"、"已发布"或"已归档"等不同状态,每个状态下的操作和行为可能会有所不同。为了优雅地处理这种情况,我们可以使用一种设计模式------状态模式(State Pattern)。
1、什么是状态模式?
状态模式是一种行为设计模式,它允许对象在其内部状态改变时改变其行为。换句话说,状态模式使得一个对象在其状态改变时能够表现得就像是改变了其类。
1.1、状态模式的组成部分
状态模式主要由以下几个部分组成:
-
上下文(Context):
- 上下文是使用状态模式的对象,它维护一个对某个状态对象的引用,并定义一个接口来与状态对象交互。
-
状态接口(State):
- 定义一个接口,表示在不同状态下的行为。每个具体状态类都实现这个接口。
-
具体状态(Concrete State):
- 每个具体状态类实现状态接口,定义该状态下的具体行为。
1.2、状态模式的优点
1.2.1、 简化代码
解释 :
状态模式通过将与状态相关的行为封装在状态类中,避免了在上下文类中使用大量的条件语句(如 if-else
或 switch
)。这使得代码更加简洁,易于理解和维护。
示例 :
假设我们有一个简单的交通信号灯系统,使用条件语句来管理信号灯的状态:
python
class TrafficLight:
def __init__(self):
self.state = "red"
def change(self):
if self.state == "red":
print("Changing from red to green.")
self.state = "green"
elif self.state == "green":
print("Changing from green to yellow.")
self.state = "yellow"
elif self.state == "yellow":
print("Changing from yellow to red.")
self.state = "red"
# 使用示例
light = TrafficLight()
light.change() # 输出: Changing from red to green.
light.change() # 输出: Changing from green to yellow.
light.change() # 输出: Changing from yellow to red.
在这个例子中,随着状态的增加,条件语句会变得越来越复杂。
使用状态模式 :
通过状态模式,我们可以将每个状态的行为封装在状态类中,简化代码结构:
python
class TrafficLightState:
def change(self):
raise NotImplementedError("You should implement this method!")
class RedState(TrafficLightState):
def change(self):
print("Changing from red to green.")
return GreenState()
class GreenState(TrafficLightState):
def change(self):
print("Changing from green to yellow.")
return YellowState()
class YellowState(TrafficLightState):
def change(self):
print("Changing from yellow to red.")
return RedState()
class TrafficLight:
def __init__(self):
self.state = RedState() # 初始状态为红灯
def change(self):
self.state = self.state.change()
# 使用示例
light = TrafficLight()
light.change() # 输出: Changing from red to green.
light.change() # 输出: Changing from green to yellow.
light.change() # 输出: Changing from yellow to red.
在这个例子中,状态的变化被封装在各个状态类中,避免了复杂的条件语句。
1.2.2、 易于扩展
解释 :
状态模式使得添加新状态变得简单,只需增加新的状态类,而不需要修改现有的代码。这符合开闭原则(对扩展开放,对修改关闭)。
示例 :
继续使用交通信号灯的例子,如果我们想要添加一个新的状态,比如"闪烁黄灯",我们只需创建一个新的状态类,而不需要修改现有的状态类或上下文类。
python
class FlashingYellowState(TrafficLightState):
def change(self):
print("Flashing yellow light. Cars should proceed with caution.")
return RedState() # 假设闪烁黄灯后返回红灯
# 更新 TrafficLight 类以支持新的状态
class TrafficLight:
def __init__(self):
self.state = RedState() # 初始状态为红灯
def change(self):
self.state = self.state.change()
# 使用示例
light = TrafficLight()
light.change() # 输出: Changing from red to green.
light.change() # 输出: Changing from green to yellow.
light.change() # 输出: Changing from yellow to red.
light.state = FlashingYellowState() # 设置为闪烁黄灯状态
light.change() # 输出: Flashing yellow light. Cars should proceed with caution.
在这个例子中,我们轻松地添加了一个新的状态,而不需要修改现有的代码。
1.2.3、 状态与行为的分离
解释 :
状态模式将状态的变化与行为的实现分离,使得代码更加清晰。每个状态类只负责实现其特定的行为,避免了将所有逻辑集中在一个类中。
示例 :
在没有使用状态模式的情况下,所有状态的行为都可能集中在一个类中,导致代码难以维护和理解。
python
class Document:
def __init__(self):
self.state = "draft"
def publish(self):
if self.state == "draft":
print("Document published.")
self.state = "published"
elif self.state == "published":
print("Document is already published.")
def edit(self):
if self.state == "draft":
print("Editing the document in draft state.")
elif self.state == "published":
print("Editing the published document.")
# 使用示例
doc = Document()
doc.edit() # 输出: Editing the document in draft state.
doc.publish() # 输出: Document published.
doc.edit() # 输出: Editing the published document.
在这个例子中,所有状态的行为都在 Document
类中实现,导致代码变得复杂。
使用状态模式 :
通过状态模式,我们可以将每个状态的行为封装在状态类中,使得代码更加清晰。
python
class DocumentState:
def publish(self):
raise NotImplementedError("You should implement this method!")
def edit(self):
raise NotImplementedError("You should implement this method!")
class DraftState(DocumentState):
def publish(self):
print("Document published.")
return PublishedState()
def edit(self):
print("Editing the document in draft state.")
class PublishedState(DocumentState):
def publish(self):
print("Document is already published.")
def edit(self):
print("Editing the published document.")
class Document:
def __init__(self):
self.state = DraftState() # 初始状态为草稿状态
def set_state(self, state):
self.state = state
def publish(self):
self.set_state(self.state.publish())
def edit(self):
self.state.edit()
# 使用示例
doc = Document()
doc.edit() # 输出: Editing the document in draft state.
doc.publish() # 输出: Document published.
doc.edit() # 输出: Editing the published document.
- 状态变化 :在
publish
方法中,状态的变化是必需的,因此需要调用set_state
来更新上下文的状态。 - 状态行为 :在
edit
方法中,状态的变化并不是必需的,直接调用当前状态的edit
方法即可。
1.3、何时使用状态模式?
状态模式特别适用于以下场景:
- 当一个对象的行为依赖于其状态,并且可以在运行时改变其状态时。
- 当需要在多个状态之间切换,并且每个状态都有不同的行为时。
- 当使用条件语句(如
if-else
或switch
)来管理状态时,代码变得复杂且难以维护时。
2、 示例 1 - 音乐播放器
假设我们有一个 音乐播放器,它可以处于以下几种状态:
- 停止(Stopped)
- 播放(Playing)
- 暂停(Paused)
python
class PlayerState:
def play(self):
raise NotImplementedError("You should implement this method!")
def pause(self):
raise NotImplementedError("You should implement this method!")
def stop(self):
raise NotImplementedError("You should implement this method!")
class StoppedState(PlayerState):
def play(self):
print("Starting playback...")
return PlayingState()
def pause(self):
print("Player is already stopped. Cannot pause.")
def stop(self):
print("Player is already stopped.")
class PlayingState(PlayerState):
def play(self):
print("Player is already playing.")
def pause(self):
print("Pausing playback...")
return PausedState()
def stop(self):
print("Stopping playback...")
return StoppedState()
class PausedState(PlayerState):
def play(self):
print("Resuming playback...")
return PlayingState()
def pause(self):
print("Player is already paused.")
def stop(self):
print("Stopping playback...")
return StoppedState()
class MusicPlayer:
def __init__(self):
self.state = StoppedState() # 初始状态为停止状态
def set_state(self, state):
self.state = state
def play(self):
self.set_state(self.state.play())
def pause(self):
self.set_state(self.state.pause())
def stop(self):
self.set_state(self.state.stop())
# 使用示例
player = MusicPlayer()
player.play() # 输出: Starting playback...
player.pause() # 输出: Pausing playback...
player.play() # 输出: Resuming playback...
player.stop() # 输出: Stopping playback...
- 状态接口 :
PlayerState
定义了play
、pause
和stop
方法。 - 具体状态 :
StoppedState
:表示停止状态,定义了在停止状态下的行为。PlayingState
:表示播放状态,定义了在播放状态下的行为。PausedState
:表示暂停状态,定义了在暂停状态下的行为。
- 上下文 :
MusicPlayer
类维护当前状态,并通过调用状态的方法来改变其行为。
3、示例 2 - 文档管理系统
假设我们有一个文档管理系统,文档可以处于以下几种状态:
- 草稿(Draft)
- 已发布(Published)
- 已归档(Archived)
python
class DocumentState:
def publish(self):
raise NotImplementedError("You should implement this method!")
def edit(self):
raise NotImplementedError("You should implement this method!")
def archive(self):
raise NotImplementedError("You should implement this method!")
class DraftState(DocumentState):
def publish(self):
print("Document published.")
return PublishedState()
def edit(self):
print("Editing the document in draft state.")
def archive(self):
print("Document cannot be archived while in draft state.")
class PublishedState(DocumentState):
def publish(self):
print("Document is already published.")
def edit(self):
print("Editing the published document.")
def archive(self):
print("Document archived.")
return ArchivedState()
class ArchivedState(DocumentState):
def publish(self):
print("Cannot publish an archived document.")
def edit(self):
print("Cannot edit an archived document.")
def archive(self):
print("Document is already archived.")
class Document:
def __init__(self):
self.state = DraftState() # 初始状态为草稿状态
def set_state(self, state):
self.state = state
def publish(self):
self.set_state(self.state.publish())
def edit(self):
self.state.edit()
def archive(self):
self.set_state(self.state.archive())
# 使用示例
doc = Document()
doc.edit() # 输出: Editing the document in draft state.
doc.publish() # 输出: Document published.
doc.edit() # 输出: Editing the published document.
doc.archive() # 输出: Document archived.
doc.publish() # 输出: Cannot publish an archived document.
- 状态接口 :
DocumentState
定义了publish
、edit
和archive
方法。 - 具体状态 :
DraftState
:表示草稿状态,允许编辑和发布,但不允许归档。PublishedState
:表示已发布状态,允许编辑和归档,但不允许再次发布。ArchivedState
:表示已归档状态,不允许编辑或发布。
- 上下文 :
Document
类维护当前状态,并通过调用状态的方法来改变其行为。