古法编程: 我要的是状态模式,策略模式不要误我大计

原来我一直想要的是状态模式,策略模式误我大计...

地铁在天地间穿过,背后的人行道,有人高声唱歌,我仰望天空,在发呆...

状态模式(State)

当一个对象的内在状态改变时,允许改变其行为

不同状态有不同的行为,虽然者很像是策略模式,但是关键区别在于状态之间是有联系的,而策略模式是相互独立的。

📌与策略模式的区别

原来我一直想要的是状态模式,策略模式误我大计...

  • 核心都是"上下文 + 策略/状态" :都有一个"主体"对象,把具体工作委托给另一个"算法/状态"对象。
  • 都消除条件判断 :都用多态(不同的策略/状态类)来代替 if-elseswitch 判断。
  • 都遵循开闭原则:增加新策略或新状态,基本不需修改主体代码。
  • 策略模式:客户端主动选择策略,策略之间互相不知道对方存在
  • 状态模式:状态自己决定下一个状态,状态之间互相知道并能转换

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

时序图(执行流程)

游戏状态切换分析

游戏中有暂停和进行中两种状态,暂停的时候有要处理的事件,游戏进行中也需要处理响应的事件,从整个系统来说,系统的状态变了,也就会有不同的行为。

下面是一段需要优化重构的代码。

相关推荐
tenggouwa2 小时前
16GB Mac 同时开 3 个 Cursor 拯救我的mac
前端·后端
ltl3 小时前
激活函数:让网络「弯下来」的非线性魔法
后端
二哈赛车手3 小时前
新人笔记---浅扒一下Spring AI的chatClient的装配流程源码
后端
犹豫的果冻布丁3 小时前
OpenSpec 完全中文教程:AI 规范驱动开发入门与实战
前端·后端
哈里谢顿3 小时前
redis的分布式设计
后端·面试
IT_陈寒3 小时前
Java的HashMap竟然不是线程安全的?刚在生产环境踩了坑
前端·人工智能·后端
字节高级特工3 小时前
MySQL数据库基础与实战指南
数据库·c++·人工智能·后端·mysql·adb
晨非辰3 小时前
吃透C++两大默认成员函数:const成员函数、 & 取地址运算符重载
java·大数据·开发语言·c++·人工智能·后端·面试