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

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

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

状态模式(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

时序图(执行流程)

游戏状态切换分析

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

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

相关推荐
fliter16 分钟前
Go设计取舍之一: goroutine 为什么保持匿名、无状态
后端
fliter23 分钟前
Go设计取舍之二: maps.Keys和Values为什么返回迭代器
后端
热心市民lcj29 分钟前
Spring Boot 整合 Caffeine 本地缓存实战
spring boot·后端·缓存
Revolution6133 分钟前
Nest.js 是什么:怎样用它写出第一个后端接口
后端·node.js·nestjs
aiopencode42 分钟前
SwiftUI Introspect生产环境完全指南:为什么它是安全可靠的选择
后端·ios
shengjk11 小时前
x86架构发展史:从8086到x86-64,一文看懂40多年CPU指令集如何改变世界
后端
小白说大模型2 小时前
Python 工程化设计模式:AI 项目中的异步流水线与策略模式实战
人工智能·python·设计模式
JackSparrow4142 小时前
前端安全之JS混淆+请求加密+请求签名以提升爬虫难度
前端·javascript·后端·爬虫·python·安全
geovindu2 小时前
go:loghelper
开发语言·后端·golang
小满zs3 小时前
Go语言第四章(类型转换)
后端·go