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));
}