当前位置: 首页 > article >正文

漫谈设计模式 [17]:状态模式

引导性开场

菜鸟:老鸟,我最近在写一个项目,遇到一个问题。我们有一个订单系统,不同的订单状态需要执行不同的操作。现在代码里充满了各种 if-else 语句,维护起来好痛苦。有没有什么好的解决办法?

老鸟:你这个问题很常见,很多人都会遇到类似的痛点。你有没有听说过状态模式?

菜鸟:状态模式?好像听过,但不太了解。

老鸟:没关系,我们可以一步步来。先讲讲你现在的实现方式吧。

渐进式介绍概念

菜鸟:好的,我现在是这样写的:

class Order:
    def __init__(self):
        self.state = "pending"
    
    def process(self):
        if self.state == "pending":
            print("Processing pending order")
            self.state = "shipped"
        elif self.state == "shipped":
            print("Order has already been shipped")
        elif self.state == "delivered":
            print("Order has already been delivered")

order = Order()
order.process()
order.process()

老鸟:我明白了。这种方式确实可以工作,但随着状态和操作的增多,代码会变得越来越复杂。我们可以用状态模式来改进这个问题。状态模式的核心思想是:将状态和行为封装在独立的状态类中,通过改变状态对象来改变对象的行为。

菜鸟:听起来有点抽象,能不能用一个简单的例子解释一下?

老鸟:当然可以。你可以把订单的状态比作交通灯,不同的灯光对应不同的行为。比如,红灯停,绿灯行,黄灯警告。每种灯光都是一种状态,不同状态下有不同的行为。

Python代码示例,逐步展开

菜鸟:明白了,那我们怎么用Python实现这个状态模式呢?

老鸟:我们可以把每种状态抽象成一个类,定义它们各自的行为。然后在订单类中维护一个当前状态对象,通过调用状态对象的方法来执行相应的操作。

第一步:定义状态接口和具体状态类

from abc import ABC, abstractmethod

class OrderState(ABC):
    @abstractmethod
    def process(self, order):
        pass

class PendingState(OrderState):
    def process(self, order):
        print("Processing pending order")
        order.state = ShippedState()

class ShippedState(OrderState):
    def process(self, order):
        print("Order has already been shipped")

class DeliveredState(OrderState):
    def process(self, order):
        print("Order has already been delivered")

菜鸟:这些类看起来很清晰,每个状态类都实现了 OrderState 接口,并定义了自己的 process 方法。

第二步:在订单类中使用状态对象

class Order:
    def __init__(self):
        self.state = PendingState()
    
    def process(self):
        self.state.process(self)

菜鸟:我明白了,我们把状态的逻辑从订单类中分离出来,每个状态类只负责自己的逻辑。订单类只需要维护一个当前状态对象,并调用它的 process 方法。

问题与反思

菜鸟:这种方式确实比 if-else 更清晰,但如果我直接修改状态对象,比如 order.state = DeliveredState(),会不会有问题?

老鸟:确实,这样会破坏状态模式的封装性。我们应该通过状态对象的方法来改变状态,而不是直接修改状态对象。你可以在状态类中添加一个方法来改变状态,比如 set_state 方法。

优化后的实现

class Order:
    def __init__(self):
        self.state = PendingState()
    
    def set_state(self, state):
        self.state = state
    
    def process(self):
        self.state.process(self)

更新状态类中的行为

class PendingState(OrderState):
    def process(self, order):
        print("Processing pending order")
        order.set_state(ShippedState())

class ShippedState(OrderState):
    def process(self, order):
        print("Order has already been shipped")

class DeliveredState(OrderState):
    def process(self, order):
        print("Order has already been delivered")

优势与适用场景

老鸟:状态模式的优势在于,它将状态逻辑分散到单独的状态类中,使得代码更加清晰和易于维护。它的适用场景包括:

  • 对象的行为依赖于其状态,并且需要在运行时根据状态改变行为。
  • 需要避免大量的条件语句来处理状态转换。

菜鸟:嗯,听起来挺有道理的。

常见误区与优化建议

老鸟:需要注意的是,状态模式也有一些常见的误区,比如:

  • 过度设计:不必要的情况下使用状态模式会增加代码复杂性。
  • 状态转换逻辑分散:状态转换逻辑分散在各个状态类中,可能会导致难以追踪。

优化建议是:在使用状态模式时,要确保确实需要这种模式,并且在设计时尽量保持状态转换逻辑的一致性和可追踪性。

总结与延伸阅读

老鸟:今天我们通过一个订单系统的例子,逐步讲解了状态模式的概念和实现。状态模式可以让你的代码更加清晰和易于维护,但在使用时也要注意避免过度设计。你可以进一步阅读《设计模式:可复用面向对象软件的基础》这本书,它详细介绍了各种设计模式,包括状态模式。

菜鸟:谢谢老鸟,今天学到了很多。我打算继续学习其他设计模式,有什么推荐的吗?

老鸟:你可以接着学习策略模式和观察者模式,它们也是非常实用的设计模式。加油!

菜鸟:好的,我会继续学习的!


http://www.kler.cn/news/294827.html

相关文章:

  • 调研-libevent
  • VitePress 自定义 CSS 指南
  • docker基础命令总结
  • 流程图符号速查:快速掌握流程图绘制要点
  • Kafka【十二】消费者拉取主题分区的分配策略
  • NISP 一级 —— 考证笔记合集
  • RISC-V (十二)系统调用
  • python网络爬虫(五)——爬取天气预报
  • 风趣图解LLMs RAG的15种设计模式-第一课
  • 自然语言处理系列六十二》神经网络算法》MLP多层感知机算法
  • 【C/C++】web服务器项目开发总结【请求 | 响应 | CGI】
  • 活动系统开发之采用设计模式与非设计模式的区别-非设计模式
  • Java stream使用与执行原理
  • 通信工程学习:什么是SSB单边带调制、VSB残留边带调制、DSB抑制载波双边带调制
  • Web前端主流的框架详解
  • 基于大数据的科研热点分析与挖掘系统
  • 数学建模_数据预处理流程(全)
  • 命名空间,using声明,指令与作用域,重载与namespace
  • 智慧工地解决方案-2
  • 架构全景视图
  • lxml官方入门教程(The lxml.etree Tutorial)翻译
  • 超越IP-Adapter!阿里提出UniPortrait,可通过文本定制生成高保真的单人或多人图像。
  • 类和对象的定义和调用演示(C++)
  • CSS-动态计算高度
  • [数据集][目标检测]街道乱堆垃圾检测数据集VOC+YOLO格式94张1类别
  • ELK学习笔记(一)——使用K8S部署ElasticSearch8.15.0集群
  • Python条件表达式优化的10个实例
  • Springboot集成WebSocket客户端,发送消息并监测心跳
  • Ansible与Docker集成:实现容器化运维自动化
  • 浙大数据结构:02-线性结构1 两个有序链表序列的合并