状态模式
本课属于 Coddy Python 学习旅程的“面向对象编程”单元。第 53 课,共 64 课。
状态模式允许对象在内部状态发生变化时改变其行为。对象会根据当前状态呈现出不同的类。
下面是交通灯的简单状态类:
class RedState:
def next_state(self, light):
print("Red -> Green")
light.state = GreenState()
def current_color(self):
return "Red"
class GreenState:
def next_state(self, light):
print("Green -> Yellow")
light.state = YellowState()
def current_color(self):
return "Green"
class YellowState:
def next_state(self, light):
print("Yellow -> Red")
light.state = RedState()
def current_color(self):
return "Yellow"每个状态都会定义切换到下一个状态时发生的情况。
创建一个保存当前状态的上下文类:
class TrafficLight:
def __init__(self):
self.state = RedState() # 从红灯开始
def change(self):
self.state.next_state(self)
def get_color(self):
return self.state.current_color()交通信号灯将行为委托给其当前状态对象。
使用交通灯:
light = TrafficLight()
print(f"Current: {light.get_color()}")
light.change() # 红灯变绿灯
print(f"Current: {light.get_color()}")
light.change() # 绿灯变黄灯
print(f"Current: {light.get_color()}")
light.change() # 黄灯变红灯
print(f"Current: {light.get_color()}")再用一个简单的播放器创建示例:
class PlayingState:
def play(self, player):
print("Already playing")
def stop(self, player):
print("Stopping music")
player.state = StoppedState()
class StoppedState:
def play(self, player):
print("Starting music")
player.state = PlayingState()
def stop(self, player):
print("Already stopped")
class MusicPlayer:
def __init__(self):
self.state = StoppedState()
def play(self):
self.state.play(self)
def stop(self):
self.state.stop(self)
player = MusicPlayer()
player.play() # 开始播放音乐
player.play() # 正在播放
player.stop() # 停止播放音乐
player.stop() # 已经停止输出:
Current: Red
Red -> Green
Current: Green
Green -> Yellow
Current: Yellow
Yellow -> Red
Current: Red
Starting music
Already playing
Stopping music
Already stopped要点:状态模式将特定状态的行为封装在单独的类中,并让上下文对象将任务委托给当前状态。状态改变时,行为也会自动改变。这样可以避免复杂的 if/else 语句,也让添加新状态变得更容易。
挑战
简单在 state.py 中为一盏只有一个按钮的灯实现状态模式。每按一次按钮,灯就会在三个状态之间循环切换:关、低亮、高亮,然后回到关。不要用针对字符串的 if 链,而是让每个状态都成为一个对象,由它决定按下按钮时会发生什么。
LampState是基类,包含press(lamp)和describe()。OffState、LowState和HighState实现这两个方法:press调用lamp.set_state(...)并传入下一个状态(从关到低亮,从低亮到高亮,从高亮到关),而describe返回Lamp is off、Lamp is on low或Lamp is on high。Lamp是上下文对象:它从OffState开始,set_state会替换状态对象,press_button会将调用委托给当前状态,而status会返回当前状态的描述。
driver.py 已锁定:它会按下按钮并输出状态。注意,Lamp 从不检查自己处于哪个状态,状态对象会自行决定。
亲手试试
from state import Lamp
# 测试用例处理程序(不要修改)
test_case = input()
lamp = Lamp()
if test_case == "initial_test":
print(lamp.status())
elif test_case == "one_press_test":
lamp.press_button()
print(lamp.status())
elif test_case == "cycle_test":
for _ in range(4):
print(lamp.status())
lamp.press_button()
elif test_case == "many_presses_test":
for _ in range(7):
lamp.press_button()
print(lamp.status())
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Python 在线编译器