设计模式(二十)状态模式
1、定义
当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。主要解决的是当控制一个对象转换的条件表达式过于复杂时的状态,即把状态的判断逻辑转移到表示不同状态的一系列类当中。
2、UML类图
其中,Context类与环境角色,用于维护一个ConcreteState子类的实例,这个实例定义当前的状态;State为抽象状态角色,定义一个接口以封装与Context的一个特定接口状态相关的行为;ConcreteState是具体状态角色,每个子类实现一个与Context的一个状态相关的行为。
(1)Context类
环境角色具有两个职责,即处理本状态必须完成的任务,即处理本状态必须完成的任务,及决定是否可以过渡到其他状态。对于环境角色,有几个不成文的约束:
- 即把状态对象声明为静态常量,有几个状态对象就声明几个状态常量;
- 环境角色具有状态抽象角色定义的所有行为,具体执行使用委托方式。
1 /** 2 * @author it-小林 3 * @desc 环境角色 4 * @date 2021年09月26日 18:20 5 */ 6 public class Context { 7 8 //定义状态 9 public final static State STATE1 = new ConcreteState1(); 10 public final static State STATE2 = new ConcreteState2(); 11 12 //当前状态 13 private State currentState; 14 15 //获得当前状态 16 public State getCurrentState() { 17 return currentState; 18 } 19 20 public void setCurrentState(State currentState) { 21 this.currentState = currentState; 22 this.currentState.setContext(this); 23 } 24 25 public void handle1() { 26 this.currentState.handle1(); 27 } 28 29 public void handle2() { 30 this.currentState.handle2(); 31 } 32 }
(2)State抽象状态类
抽象环境中声明一个环境角色,提供各个状态类自行访问,并且提供所有状态的抽象行为,由各个实现类实现。
1 /** 2 * @author it-小林 3 * @desc state抽象状态类 4 * @date 2021年09月26日 18:20 5 */ 6 public abstract class State { 7 8 protected Context context; 9 10 public void setContext(Context context){ 11 this.context = context; 12 } 13 14 /** 15 * 行为1 16 */ 17 public abstract void handle1(); 18 19 /** 20 * 行为2 21 */ 22 public abstract void handle2(); 23 }
(3)具体状态
具体状态实现,这里以定义ConcreteState1和ConcreteState2两个具体状态类为例。
1 /** 2 * @author it-小林 3 * @desc 具体类1 4 * @date 2021年09月26日 18:28 5 */ 6 public class ConcreteState1 extends State{ 7 @Override 8 public void handle1() { 9 System.out.println("ConcreteState1 的 handle1 方法"); 10 } 11 12 @Override 13 public void handle2() { 14 System.out.println("ConcreteState1 的 handle2 方法"); 15 } 16 }
1 /** 2 * @author it-小林 3 * @desc 具体类2 4 * @date 2021年09月26日 18:29 5 */ 6 public class ConcreteState2 extends State{ 7 @Override 8 public void handle1() { 9 System.out.println("ConcreteState2 的 handle1 方法"); 10 } 11 12 @Override 13 public void handle2() { 14 System.out.println("ConcreteState2 的 handle2 方法"); 15 } 16 }
(4)Client客户端
定义Context环境角色,初始化具体状态1,执行行为观察结果。
1 /** 2 * @author it-小林 3 * @desc 客户端 4 * @date 2021年09月26日 18:30 5 */ 6 public class Client { 7 public static void main(String[] args) { 8 //定义环境角色 9 Context context = new Context(); 10 //初始化状态 11 context.setCurrentState(new ConcreteState1()); 12 //行为执行 13 context.handle1(); 14 context.handle2(); 15 16 //初始化状态 17 context.setCurrentState(new ConcreteState2()); 18 //行为执行 19 context.handle1(); 20 context.handle2(); 21 } 22 }
运行结果:
3、优缺点
优点:
- 结构清晰,避免了过多的switch case 或if else语句的使用;
- 很好地体现了开闭原则和单一职责原则,想要增加状态就增加子类,想要修改状态就修改子类即可;
- 封装性非常好,状态变化放置到了类的内部来实现,外部调用不需要知道类内部如何实现状态和行为的变换。
缺点:
- 子类太多,也即类膨胀。
4、使用场景
- 行为随状态改变而改变的场景;
- 条件、分支判断语句的替代者。
5、实例
- 电梯,有运行状态、开门状态、闭门状态、停止状态等;
- 运动员可以有正常状态、非正常状态和超长状态。
7、注意事项
- 在行为受状态约束的情况下可以使用状态模式,使用时对象的状态最好不要超过5个。
本文来自博客园,作者:it-小林,转载请注明原文链接:https://www.cnblogs.com/linruitao/p/15067873.html