设计模式(二十)状态模式

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个。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

     

posted @ 2021-09-27 09:59  it-小林  阅读(29)  评论(0编辑  收藏  举报