【状态模式】
当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。
状态模式的核心是封装,状态的变更引起了行为的变更,从外部看起来好像这个对象对应的类发生了改变一样。
状态模式的UML类图与策略模式一样。状态模式也由三部分组成:
* 抽象状态角色 State
接口或抽象类,负责对象状态定义,并且封装环境角色以实现状态切换。
* 具体状态角色 ConcreteState
每一个具体状态必须完成两个职责:本状态的行为管理以及趋向状态处理,即:本状态要做的事情,以及本状态如何过渡到其它状态。
* 环境角色 Context
定义客户端需要的接口,并且负责具体状态的切换。
【状态模式 例子】
package com.Higgin.State; /** * 水的状态 */ interface WaterState{ public void printState(); } /** * 固态水 */ class SolidWaterState implements WaterState{ @Override public void printState() { System.out.println("0°C以下,水是固态的..."); } } /** * 液态水 */ class LiquidWaterState implements WaterState{ @Override public void printState() { System.out.println("0°C~100°C之间,水是液态的..."); } } /** * 气态水 */ class GasWaterState implements WaterState{ @Override public void printState() { System.out.println("100°C以上,水是气态的..."); } } /** * 水状态的上下文类 */ class WaterContext{ private WaterState waterState; public void setState(int temp){ if(temp<=0){ //温度小于等于0°C,初始化为固态 waterState=new SolidWaterState(); }else if(temp>=100){ //温度在0~100°C之间,初始化为液态 waterState=new GasWaterState(); }else{ //温度在100°C及以上,初始化为气态 waterState=new LiquidWaterState(); } } //得到当前 水的具体状态类 public WaterState getState(){ return this.waterState; } } public class TestState { public static void main(String[] args) { WaterContext wc=new WaterContext(); wc.setState(18); WaterState ws=wc.getState(); ws.printState(); } }
【运行结果】
【状态模式 优点】
* 结构清晰
避免了过多的switch...case或if...else语句的使用,避免了程序的复杂性,提高了系统的可维护性。
* 遵循设计原则
很好地体现了开闭原则和单一职责原则,每个状态都是一个子类,要增加状态就增加子类,需要修改状态,修改对应的子类即可。
* 封装性良好
状态变换放置到类的内部实现,外部的调用不用知道类内部是如何实现状态和行为的变换。
【状态模式 缺点】
缺点就是抽象状态的子类会太多,导致类膨胀。如果一个事物有多个状态也很正常,如果完全使用状态模式会有太多的子类,不便于管理。(有一个思路:在数据库中建立一个状态表,然后根据状态执相应的操作。)
【状态模式 使用场景】
* 行为随状态改变而发生改变的场景
这也是状态模式的根本出发点,例如权限设计,人员的状态不同即使执行相同的操作结果也会不同,在这种情况下可以考虑使用状态模式。
* 条件、分支判断语句的替换者
在程序中大量使用switch语句或if判断语句会导致程序结构不清晰,逻辑混乱,使用状态模式可以很好地规避这一问题,通过扩展子类实现了条件判断处理。
【状态模式 注意事项】
状态模式适用于当某个对象在它的状态发生改变时,它的行为也随着发生比较大的改变,也就是说在行为受约束的情况下可以是会用状态模式,而且使用时,对象的状态最好不要超过5个。
【 策略模式 与 状态模式 区别!!】
* 封装的不同
[ 策略模式 ]封装的是不同的算法,算法之间没有交互,以达到算法可以自由切换的目的。
[ 状态模式 ]封装的是不同的状态,以达到状态岁切换行为随之发生改变的目的。
两者都有变换的行为,但是两者的目标是不同的。
* 环境角色的职责不同。(两者都有一个Context环境角色类,或上下文类)
[ 策略模式 ]旨在解决内部算法如何改变的问题,即将内部算法的改变对外界的影响降低到最小,保证算法的可自由切换。
[ 状态模式 ]对外暴露的是行为,状态的变化一般由环境角色和具体的状态共同完成的,也就是说状态模式封装了状态的变化而暴露了不同的行为或行为结果。
* 应用场景的不同
[ 策略模式 ]是一系列平行的、可以相互替换的算法封装后的结构。
[ 状态模式 ]则要求有一系列变化的场景,他要求是有状态且有行为的场景,如果只有状态而没有行为,则状态的变化就是去了意义。
* 复杂度不同
[ 策略模式 ]结构较为简单,扩展比较容易,代码较为容易阅读。
[ 状态模式 ]一般较为复杂,因为它需要从两个角色看到一个对象状态和行为的改变,也就是说它封装的是变化。