
设计模式-状态模式(State)
设计模式-状态模式
允许对象在内部状态改变的时候改变它的行为,对象看起来好像修改了它的类。通俗地说就是把所有行为包装在不同的类状态对象里,每一个状态对象都是抽象状态类的一个子类。
认识状态模式
所谓对象的状态,通常指的就是对象实例的属性的值;而行为指的就是对象的功能,再具体点说,行为大多可以对应到方法上。
状态模式的功能就是分离状态的行为,通过维护状态的变化,来调用不同状态对应的不同功能。也就是说,状态和行为是相关联的,它们的关系可以描述为:状态决定行为。
由于状态是在运行期被改变的,因此行为也会在运行期根据状态的改变而改变。
涉及角色
● 环境上下文(Context)角色:包含客户端所有感兴趣的功能状态,并且持有一个具体状态的实例,这个具体状态的实例就是当前环境对象的现有状态。
● 抽象状态(State)角色:定义一个所有具体状态的共同接口,用来封装环境角色对象的一个特定状态的行为。
● 具体状态(ConcreteState):处理来自 Context 的请求,每个具体状态类都实现了环境的一个状态对应的行为特性。
场景模拟
适合在将各种不同状态转换有不同行为的场景,避免一堆的if else。将功能委托到状态类中去,代码清晰降低耦合,同时易于拓展。
假设现在一个肥宅程序猿下班了,去自动售货机买「肥宅汽水」回去喝。自动售货机需要投币即可自动出售。
1.默认初始化是「售罄状态」,添加汽水进入售货机后变成「没有硬币」状态。
2.投入硬币则进入「有硬币」状态,判断是否有汽水,有则进入「售出状态」售出汽水,售出后还有剩余则恢复到「没有硬币」状态。否则将硬币退回,并且进入汽水「售罄状态」。
现在我们可以抽象一个售货机充当 Context 角色,投币行为是 请求入口,投币后售货机会发生很多状态转换。状态分别有:售罄、有硬币、无硬币、售出。
假如我们不用状态模式,那么就要写一堆判断条件。代码也不可拓展与维护。新增一种状态,要修改所有的代码。
所有的请求都会委托到对应的状态类,环境角色拥有所有的状态类。
代码实现
首先我们创建一个 MachineState 接口,所有的状态实现该接口。
接着我们定义无硬币状态 NoCoinState 用于处理无硬币状态的行为。
有硬币状态下的行为,也就是投币后触发的行为。同时将状态切换到销售状态,并委托到对应状态处理。
售出货物状态,售出后判断是否售罄进入不同的状态。
- 若汽水数量 > 0,状态变成无硬币状态。
- 否则进入售罄状态,这样客户再投币就可以继续执行销售还是提示售罄退回硬币。
售罄状态行为
最后定义我们的自动售货机
定义我们的客户端
测试结果
总结
从上面可以看出,环境类Context的行为request()是委派给某一个具体状态类的。通过使用多态性原则,
可以动态改变环境类Context的属性State的内容,使其从指向一个具体状态类变换到指向另一个具体状态类,
从而使环境类的行为request()由不同的具体状态类来执行。
策略模式与状态模式对比
● 状态模式:不同的状态标表示不同的行为,对应不同的处理方式。
● 策略模式:同一个行为,不同处理。因此在同一个行为发生的时候,可以根据条件挑选任意一个实现来进行相应的处理。
关于策略模式,读者可以阅读历史文章-策略模式。
文章转载自公众号:码哥字节
