【状态机实现】前置——设计模式中的孪生兄弟(状态模式和策略模式)
什么是行为型设计模式?
一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
一、状态模式
状态模式(State Pattern)是一种行为型设计模式,允许一个对象在其内部状态改变时改变其行为。这种模式通过将每个状态封装为一个单独的类来实现状态的转换。
1.1.状态模式用途:
状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。
1.2.为何需要状态模式:
封装状态转换:状态模式将所有与特定状态相关的行为封装在单个状态对象中,易于管理和修改。
简化条件逻辑:避免使用大量的条件语句来处理状态转换逻辑,使代码更加清晰。
提高可扩展性:新增状态时,只需添加新的状态类而无需修改现有代码,遵循开闭原则。
1.3.状态模式的组成:
上下文(Context)
定义:上下文持有一个状态对象的引用,定义了客户程序与状态对象交互的接口。
职责:维护当前状态,根据当前状态调用相应的行为。
状态接口(State)
定义:状态接口定义了一个或多个方法,用于封装与特定状态相关的行为。
职责:作为所有具体状态类的共同接口。
具体状态(Concrete State)
定义:具体状态类实现状态接口,并根据状态的具体行为来实现这些方法。
职责:定义在特定状态下对象的行为。
角色之间的交互
状态维护:上下文通过持有状态对象的引用来维护当前状态。
状态转换:当对象的状态需要改变时,上下文会替换状态对象,从而改变行为。
行为执行:上下文通过委托给当前状态对象来执行相关的行为。
二、策略模式
一种行为型设计模式,它定义了一系列算法或策略,并将每个算法封装在独立的类中,使得它们可以互相替换或独立于使用它的客户而变化。
2.1.业务场景
假设有这样的业务场景,大数据系统把文件推送过来,根据不同类型采取不同的解析方式。多数的小伙伴就会写出以下的代码:
if(type=="A"){//按照A格式解析
}else if(type=="B"){//按B格式解析
}else{//按照默认格式解析
}
就是以上代码,违背了面向对象编程的开闭原则以及单一原则。
● 开闭原则(对于扩展是开放的,但是对于修改是封闭的)
● 单一原则(规定一个类应该只有一个发生变化的原因)
2.2.适用场景
在一个系统里面有许多类,它们之间的区别仅在于它们的行为,使用策略模式可以动态地让一个对象在许多行为中选择一种行为;一个系统需要动态地在几种算法中选择一种; 避免使用难以维护的多重条件选择语句;希望在具体策略类中封装 算法和与相关的数据结构。例如:
● 算法动态切换(如支付方式、排序策略)。
● 避免多重条件判断(将条件逻辑封装为具体策略类)。
2.3.策略模式的结构
1.抽象策略类 Strategy Interface):定义所有支持的策略或行为的公共接口。这是一个抽象类或接口,通常只有一个方法,用于执行算法。
2.具体策略类(Concrete Strategy Classes):实现了策略接口的类,每个类都代表一种具体的算法或行为。
3.环境类(Context):又称上下文,上下文包含
● 策略接口声明的成员变量
● 注入构造方法为该成员变量赋值
● 持有一个策略类的引用,最终给客户端调用。该方法通过接口变量调用对应的具体策略
三、区别
在行为类设计模式中,状态模式和策略模式是亲兄弟,两者非常相似,我们再次看看两者的简易通用类图,把两者放在一起比较一下,如图所示:
讲真,我觉得它们都差不多啊,好难区别啊!!!
不过,虽然讲不出来它们的区别是什么,但是有个例子可以很好的描述它们的区别
- 状态模式:这个模式就好比员工申请离职单的流程,离职单到直接上级,这个状态就是直接上级批示,等直接上级审阅之后,通过了就到下一个状态。这一个个状态对应不同的处理,这是有顺序要求的。
- 策略模式:这个模式好比于你假期要出国游玩,有日本、美国、新加坡等国家,你每到一个国家就执行不同的游玩策略,可以先去日本,也可以先去美国,没有顺序要求。
简单记:策略是选择,状态是流转。
对比表格
维度 | 策略模式 (Strategy Pattern) | 状态模式 (State Pattern) |
---|---|---|
意图 | 封装和互换一系列算法,使算法独立于使用它的客户端而变化。 | 允许一个对象在其内部状态改变时改变它的行为,对象看起来好像修改了它的类。 |
核心思想 | “选择”行为。客户端主动选择一个合适的策略来完成一项任务。 | “状态”驱动行为。对象的行为由当前状态决定,并且状态会根据规则自动转换。 |
上下文角色 | 上下文对策略一无所知,它只是简单地调用策略对象的通用接口。 | 上下文知道状态,并可能持有所有状态对象的引用,以便进行状态切换。 |
依赖关系 | 策略之间通常彼此独立,不知道其他策略的存在。 | 状态对象通常知道其他状态,并负责将自己切换到下一个状态(或由上下文根据状态对象的指示来切换)。 |
控制权 | 由客户端(调用者) 决定使用哪个策略。控制权在外部。 | 状态转换的规则封装在状态类或上下文中。控制权在内部状态机里。 |
生命周期 | 策略对象通常在需要时才被客户端创建和设置,之后可能被替换。它们是无状态的工具。 | 状态对象经常被共享和重用(通常实现为享元)。它们代表了一个状态,这个状态本身可能包含数据。 |
类比 | 支付方式:出门购物,你可以主动选择用支付宝、信用卡还是现金。这些是策略。 | 电风扇档位:你按一下按钮(触发事件),风扇从“关闭”状态切换到“一档”状态,再按一下切换到“二档”。档位(状态)决定了风速(行为),且切换是顺序的、有规则的。 |