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

漫谈设计模式 [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, abstractmethodclass OrderState(ABC):@abstractmethoddef process(self, order):passclass 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 = statedef 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")

优势与适用场景

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

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

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

常见误区与优化建议

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

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

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

总结与延伸阅读

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

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

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

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

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • ✨机器学习笔记(二)—— 线性回归、代价函数、梯度下降
  • Windows本地制作nginx证书
  • python中的循环结构
  • MonoHuman: Animatable Human Neural Field from Monocular Video 精读
  • 树莓派5_opencv笔记27:Opencv录制视频(无声音)
  • 使用Spring Boot集成Spring Data JPA和单例模式构建库存管理系统
  • v0.dev快速开发
  • 两数之和--力扣1
  • JS手写实现深拷贝
  • 深入探究 Spring 的扫描原理
  • 探索国产编程工具:如何实现工作效率翻倍
  • VMware安装Ubuntu虚拟机
  • linux 安装redis
  • 以太网--TCP/IP协议(一)
  • “阡陌云旅”黄河九省文化旅游平台
  • 【技术性】Search知识
  • Flex布局到底解决了什么问题
  • JAVA SE 6 GC调优笔记
  • JDK9: 集成 Jshell 和 Maven 项目.
  • PHP CLI应用的调试原理
  • Phpstorm怎样批量删除空行?
  • 第三十一到第三十三天:我是精明的小卖家(一)
  • 构建二叉树进行数值数组的去重及优化
  • 前端性能优化——回流与重绘
  • 深度学习中的信息论知识详解
  • 思维导图—你不知道的JavaScript中卷
  • 微信开放平台全网发布【失败】的几点排查方法
  • 一文看透浏览器架构
  • hi-nginx-1.3.4编译安装
  • ​2021半年盘点,不想你错过的重磅新书
  • ​Linux Ubuntu环境下使用docker构建spark运行环境(超级详细)
  • ​Z时代时尚SUV新宠:起亚赛图斯值不值得年轻人买?
  • ​人工智能之父图灵诞辰纪念日,一起来看最受读者欢迎的AI技术好书
  • ​探讨元宇宙和VR虚拟现实之间的区别​
  • ​用户画像从0到100的构建思路
  • ​云纳万物 · 数皆有言|2021 七牛云战略发布会启幕,邀您赴约
  • # 安徽锐锋科技IDMS系统简介
  • #VERDI# 关于如何查看FSM状态机的方法
  • (02)Unity使用在线AI大模型(调用Python)
  • (zhuan) 一些RL的文献(及笔记)
  • (多级缓存)缓存同步
  • (附源码)springboot金融新闻信息服务系统 毕业设计651450
  • (附源码)springboot炼糖厂地磅全自动控制系统 毕业设计 341357
  • (附源码)基于ssm的模具配件账单管理系统 毕业设计 081848
  • (六)库存超卖案例实战——使用mysql分布式锁解决“超卖”问题
  • (排序详解之 堆排序)
  • (限时免费)震惊!流落人间的haproxy宝典被找到了!一切玄妙尽在此处!
  • (原创)攻击方式学习之(4) - 拒绝服务(DOS/DDOS/DRDOS)
  • (转)linux 命令大全
  • (转)socket Aio demo
  • (转)程序员疫苗:代码注入
  • (最简单,详细,直接上手)uniapp/vue中英文多语言切换
  • **登录+JWT+异常处理+拦截器+ThreadLocal-开发思想与代码实现**
  • ./indexer: error while loading shared libraries: libmysqlclient.so.18: cannot open shared object fil
  • .bat批处理(六):替换字符串中匹配的子串