2022年2月17日
状态模式和策略模式
这两个模式常常可以拿来做对比,两个比较相似。
状态模式,对于已经定义好的状态,如果状态变化,那么后续的操作是固定的,是“自动”的,“无感知”的,也就是说没有一个策略的选择,而是状态流转时候,这个状态下有哪些可行的操作是固定的。
策略模式主要是对算法(策略)的封装,在不同场景下,选用不同的算法,使用的是setStrategy(xxx),来设置某种策略,这个策略就是一整个完整的流程动作。
策略模式 VS 状态模式 | 菜鸟教程 (runoob.com)
状态模式 意图:允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。 主要解决:对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。 何时使用:代码中包含大量与对象状态有关的条件语句。 如何解决:将各种具体的状态类抽象出来。 优点: 1、封装了转换规则。 2、枚举可能的状态,在枚举状态之前需要确定状态种类。 3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。 4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。 5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。 缺点: 1、状态模式的使用必然会增加系统类和对象的个数。 2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。 3、状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。 使用场景: 1、行为随状态改变而改变的场景。 2、条件、分支语句的代替者。 注意事项:在行为受状态约束的时候使用状态模式,而且状态不超过 5 个。 上面文章中,糖果机的例子就很好,显示使用if else来处理整个流程,然后使用状态模式来改写。 改写前,投币这个动作,会判断不同的状态,来做不同的处理 /** * 投币 */ public void insertQuarter() { if(NO_QUARTER == state){ System.out.println("投币"); state = HAS_QUARTER; } else if(HAS_QUARTER == state){ System.out.println("请不要重复投币!"); returnQuarter(); } else if(SOLD == state){ System.out.println("已投币,请等待糖果"); returnQuarter(); }else if(SOLD_OUT == state){ System.out.println("糖果已经售尽"); returnQuarter(); } } 改写后,每个状态都会有一个投币的动作,但是投币的动作产生的结果是不同的 public abstract class State { /** * 投币 */ public abstract void insertQuarter(); /** * 退币 */ public abstract void ejectQuarter(); /** * 转动出糖曲轴 */ public abstract void turnCrank(); /** * 发糖 */ public abstract void dispense(); /** * 退还硬币 */ protected void returnQuarter() { System.out.println("退币……"); } } 简单的理解,if else是在动作里面,判断状态,每个状态触发后结果不同,状态模式是在特定状态下面触发动作,这个动作会产生什么结果已经被提前固定下来了。
策略模式的例子 创建一个接口 Strategy.java public interface Strategy { public int doOperation(int num1, int num2); } 创建实现接口的实体类。 OperationAdd.java public class OperationAdd implements Strategy{ @Override public int doOperation(int num1, int num2) { return num1 + num2; } } OperationSubtract.java public class OperationSubtract implements Strategy{ @Override public int doOperation(int num1, int num2) { return num1 - num2; } } OperationMultiply.java public class OperationMultiply implements Strategy{ @Override public int doOperation(int num1, int num2) { return num1 * num2; } } 上下问,实现对策略的设置 public class Context { private Strategy strategy; public Context(){ } public SetStrategy(Strategy strategy){ this.strategy = strategy; } public int executeStrategy(int num1, int num2){ return strategy.doOperation(num1, num2); } } 调用: public static void main(String[] args) { Context context = new Context(); context.SetStrategy(new OperationAdd()); System.out.println("10 + 5 = " + context.executeStrategy(10, 5)); context.SetStrategy(new OperationSubtract()); System.out.println("10 - 5 = " + context.executeStrategy(10, 5)); context.SetStrategy(new OperationMultiply()); System.out.println("10 * 5 = " + context.executeStrategy(10, 5)); }