原来我一直想要的是状态模式,策略模式误我大计...
地铁在天地间穿过,背后的人行道,有人高声唱歌,我仰望天空,在发呆...

状态模式(State)
当一个对象的内在状态改变时,允许改变其行为
不同状态有不同的行为,虽然者很像是策略模式,但是关键区别在于状态之间是有联系的,而策略模式是相互独立的。

📌与策略模式的区别
原来我一直想要的是状态模式,策略模式误我大计...
- 核心都是"上下文 + 策略/状态" :都有一个"主体"对象,把具体工作委托给另一个"算法/状态"对象。
- 都消除条件判断 :都用多态(不同的策略/状态类)来代替
if-else或switch判断。 - 都遵循开闭原则:增加新策略或新状态,基本不需修改主体代码。
- 策略模式:客户端主动选择策略,策略之间互相不知道对方存在
- 状态模式:状态自己决定下一个状态,状态之间互相知道并能转换
Radio状态切换切换
收音机有两个工作模式:AM(调幅) 和 FM(调频) 。在不同模式(状态))下,有不同的功能(行为):
- 收听的频道列表不同(AM: 530/540/550,FM: 90.1/91.1/92.1)
- 点击「扫描」按钮时,切换到该模式下的下一个频道
- 点击「切换」按钮时,在 AM 和 FM 之间相互转换

Python实现
用python写这种思想设计就是舒服,用Java就太牛刀杀鸡了。---来自Java古法的感悟。
python
from __future__ import annotations
from abc import ABC, abstractmethod
class BaseState(ABC):
def __init__(self, radio: Radio):
"""每个子类都要持有上下文,通过上下文改变状态"""
self.radio = radio
self.pos = 0
def scan(self):
"""扫描"""
self.pos = (self.pos + 1) % len(self.stations)
print(f"Radio 收听的是 {self.name} 频道: {self.stations[self.pos]}")
@abstractmethod
def toggle_amfm(self):
"""改变上下文状态的方法
抽象方法强制子类实现,让子类状态转向下一个状态
""" ...
class AmState(BaseState):
def __init__(self, radio: Radio):
super().__init__(radio)
self.name = "AM"
self.stations = ["530", "540", "550"]
def toggle_amfm(self):
"""转化为FM"""
self.radio.state = RadioState.FM
class FmState(BaseState):
def __init__(self, radio: Radio):
super().__init__(radio)
self.name = "FM"
self.stations = ["90.1", "91.1", "92.1"]
def toggle_amfm(self):
"""转化为AM"""
self.radio.state = RadioState.AM
from enum import Enum
class RadioState(Enum):
AM = "AM"
FM = "FM"
OTHER = "NOT Support Yet"
class Radio:
def __init__(self):
# 这里有点像策略,但是与策略相比,具体执行是在维护的这几个元素之间相互切换的
self._states = {
RadioState.AM: AmState(self),
RadioState.FM: FmState(self)
}
self._state = self._states[RadioState.AM]
def toggle_amfm(self):
"""切换AMFM
让状态流转,具体怎么流转,让子类自己去处理
"""
self.state.toggle_amfm()
def scan(self):
self.state.scan()
@property
def state(self):
return self._state
@state.setter
def state(self, state_type: RadioState):
if state_type not in self._states:
raise ValueError(f"{state_type} is not a valid state")
self._state = self._states[state_type]
if __name__ == '__main__':
r = Radio()
from typing import Callable
actions: list[Callable] = [r.scan] * 2 + [r.toggle_amfm] + [r.scan] * 2
[c() for c in actions]
输出
txt
Radio 收听的是 AM 频道: 540
Radio 收听的是 AM 频道: 550
Radio 收听的是 FM 频道: 91.1
Radio 收听的是 FM 频道: 92.1
时序图(执行流程)

游戏状态切换分析
游戏中有暂停和进行中两种状态,暂停的时候有要处理的事件,游戏进行中也需要处理响应的事件,从整个系统来说,系统的状态变了,也就会有不同的行为。
下面是一段需要优化重构的代码。
