状态模式的理解和示例
一、是什么
1. 定义: 封装了基于状态的行为,并使用委托在行为之间切换
2. 好处: 通过将每个状态封装到类中,将以后需要做的任何改变局部化
3. 缺点: 使用状态类通常会导致设计类的数量大量增加
4. 类图如上,和策略模式的类图相同,目的不同,策略是为了封装互换的行为,用委托来解耦,状态模式的目的是将状态封装成类,用委托来切换状态
二、示例
场景:假设冲一杯咖啡的步骤是,1. 拿一个空杯子 2. 往杯子中添加速溶咖啡 3. 往杯子中加水
该场景中有三个状态: 1. 空杯子 2. 装有速溶咖啡的杯子 2. 装水的杯子
原来的实现:
写了个大概的假代码, 这里只有拿杯子的方法,里面就有了四个if判断, 后面的方法还是继续if判断,相对麻烦一点, 当然最重要的是如果以后要变化步骤的话,整个类都在影响范围之类。而状态模式在这里可以帮我们将变化局部化
final static int NO_CUP = 0 // 还没有杯子的状态 final static int EMPTY_CUP = 1 // 空杯 final static int INSTANT_COFFEE_CUP = 2 // 装有速溶咖啡粉的杯子 final static int ENJOY_CUP = 3 // 冲好咖啡, 美滋滋的杯子 // 拿杯子的方法 public void takeCup() { if (state == NO_CUP) { // 此时没有杯子, 所以我就拿了一个空杯子 state = EMPTY_CUP; } else if (state == EMPTY_CUP) { // 已经有一个空杯子了, 不需要再拿了 } else if (state == INSTANT_COFFEE_CUP) { // 已经有一个装有速溶咖啡粉的杯子, 不需要再拿了 } else if (state == ENJOY_CUP) { // 已经冲好咖啡了, 不需要再拿了 } }
现有的实现:
1. 状态类
1. 1 状态类的接口
/** * 状态接口 */ public interface State { /** * 1. 拿杯子 */ void takeCup(); /** * 2. 往杯子中添加速溶咖啡 */ void addInstantCoffe(); /** * 3. 往杯子中加水 */ void addWater(); /** * 4. 尽情的享受咖啡 */ void enjoyCoffe(); }
1.2 没有杯子的状态类
/** * 0. 没有杯子的状态 */ public class NoCupState implements State { private MakeCoffe makeCoffe; public NoCupState(MakeCoffe makeCoffe) { this.makeCoffe = makeCoffe; } @Override public void takeCup() { makeCoffe.state = makeCoffe.emptyCupState; System.out.println("拿了一个杯子"); } @Override public void addInstantCoffe() { System.out.println("还没有一个杯子, 需要拿个杯子"); } @Override public void addWater() { System.out.println("还没有一个杯子, 需要拿个杯子"); } @Override public void enjoyCoffe() { System.out.println("现在还没有杯子, 享受不了啊"); } }
1.3 空杯子的状态
/** * 1. 有个空杯子的状态 */ public class EmptyCupState implements State { private MakeCoffe makeCoffe; public EmptyCupState(MakeCoffe makeCoffe) { this.makeCoffe = makeCoffe; } @Override public void takeCup() { System.out.println("已经有个空杯子了, 不需要再"); } @Override public void addInstantCoffe() { this.makeCoffe.state = makeCoffe.instantCoffeCupState; System.out.println("往杯子加了速溶咖啡"); } @Override public void addWater() { System.out.println("杯子中还需要先加速溶咖啡粉, 再加水"); } @Override public void enjoyCoffe() { System.out.println("现在还是空杯子, 享受不了啊"); } }
1.4 加了速溶咖啡的状态
/** * 2. 加了速溶咖啡的状态 */ public class InstantCoffeCupState implements State { private MakeCoffe makeCoffe; public InstantCoffeCupState(MakeCoffe makeCoffe) { this.makeCoffe = makeCoffe; } @Override public void takeCup() { System.out.println("杯子中已经加了速溶咖啡了, 不需要在拿一个了"); } @Override public void addInstantCoffe() { System.out.println("杯子中已经加了速溶咖啡了, 不需要再放速溶咖啡了"); } @Override public void addWater() { makeCoffe.state = makeCoffe.coffeOkState; System.out.println("往有速溶咖啡的杯子里, 加水"); } @Override public void enjoyCoffe() { System.out.println("现在杯子中还没加水, 享受不了啊"); } }
1.5 加完水,咖啡冲好的状态,享受咖啡
/** * 4. 咖啡冲好, 享受咖啡 */ public class CoffeOkState implements State { @Override public void takeCup() { System.out.println("咖啡已经冲好了, 不需要再拿一个杯子了"); } @Override public void addInstantCoffe() { System.out.println("咖啡已经冲好了, 不需要再加速溶咖啡了"); } @Override public void addWater() { System.out.println("咖啡已经冲好了, 不需要再加水了"); } @Override public void enjoyCoffe() { System.out.println("享受咖啡咯"); } }
2. 制作咖啡的类
/** * 制作咖啡的类 */ public class MakeCoffe { /** * 这杯咖啡的状态 */ public State state; /** * 没有杯子状态 */ public NoCupState noCupState; /** * 有一个空杯子状态 */ public EmptyCupState emptyCupState; /** * 杯子里有速溶咖啡粉状态 */ public InstantCoffeCupState instantCoffeCupState; /** * 冲好咖啡状态 */ public CoffeOkState coffeOkState; public MakeCoffe() { this.noCupState = new NoCupState(this); this.emptyCupState = new EmptyCupState(this); this.instantCoffeCupState = new InstantCoffeCupState(this); this.coffeOkState = new CoffeOkState(); // 设置默认状态 this.state = this.noCupState; } // 拿杯子 public void takeCup() { state.takeCup(); } // 加入速溶咖啡 public void addInstantCoffe() { state.addInstantCoffe(); } // 加水 public void addWater() { state.addWater(); } public void enjoyCoffe() { state.enjoyCoffe(); } }
3. 测试
/** * 享受咖啡测试类 */ public class EnjoyCoffeMain { public static void main(String[] args) { MakeCoffe makeCoffe = new MakeCoffe(); makeCoffe.takeCup(); makeCoffe.addInstantCoffe(); makeCoffe.addWater(); makeCoffe.enjoyCoffe(); } } // 控制台显示 拿了一个杯子 往杯子加了速溶咖啡 往有速溶咖啡的杯子里, 加水 享受咖啡咯
1. 恭喜这个程序猿在没有写很多IF判断的情况下,成功享受到咖啡, 状态模式这里我觉得好处就是可以将变化分开封装,以后 要是某个状态中的操作改了,不需要查找整个IF了,找到对应类修改。
2. 或者以后添加某个状态的话,如卡布奇诺需要加奶加糖等,就不需要修改IF, 而是添加状态,修改部分状态中的代码
3. 带来的缺点就是,增加了很多的类
三、总结
想想自己两年前理解的状态的模式,现在比以前更理解一点了