示例代码git地址:https://gitee.com/zyxscuec/Design-pattern.git
在状态模式(State Pattern)中,类的行为是基于它的状态改变的。这种类型的设计模式属于行为型模式。
在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。
主要解决:对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。
何时使用:代码中包含大量与对象状态有关的条件语句。
如何解决:将各种具体的状态类抽象出来。
关键代码:通常命令模式的接口中只有一个方法。而状态模式的接口中有一个或者多个方法。而且,状态模式的实现类的方法,一般返回值,或者是改变实例变量的值。也就是说,状态模式一般和对象的状态有关。实现类的方法有不同的功能,覆盖接口中的方法。状态模式和命令模式一样,也可以用于消除 if…else 等条件选择语句。
1、行为随状态改变而改变的场景。
2、条件、分支语句的代替者。
注意事项:在行为受状态约束的时候使用状态模式,而且状态不超过 5 个。
我们将创建一个 State 接口和实现了 State 接口的实体状态类。Context 是一个带有某个状态的类。
StatePatternDemo,我们的演示类使用 Context 和状态对象来演示 Context 在状态改变时的行为变化。
创建一个接口。
package com.alibaba.design.statepattern;
/**
* @author zhouyanxiang
* @create 2020-08-2020/8/1-23:24
*/
public interface State {
public void doAction(Context context);
}
创建 Context 类。
package com.alibaba.design.statepattern;
/**
* @author zhouyanxiang
* @create 2020-08-2020/8/1-23:25
*/
public class Context {
private State state;
public Context(){
state = null;
}
public void setState(State state){
this.state = state;
}
public State getState(){
return state;
}
}
创建实现接口的实体类。
package com.alibaba.design.statepattern;
/**
* @author zhouyanxiang
* @create 2020-08-2020/8/1-23:25
*/
public class StartState implements State {
public void doAction(Context context) {
System.out.println("Player is in start state");
context.setState(this);
}
@Override
public String toString(){
return "Start State";
}
}
package com.alibaba.design.statepattern;
/**
* @author zhouyanxiang
* @create 2020-08-2020/8/1-23:26
*/
public class StopState implements State {
public void doAction(Context context) {
System.out.println("Player is in stop state");
context.setState(this);
}
@Override
public String toString(){
return "Stop State";
}
}
使用 Context 来查看当状态 State 改变时的行为变化。
package com.alibaba.design.statepattern;
/**
* @author zhouyanxiang
* @create 2020-08-2020/8/1-23:26
*/
public class StatePatternDemo {
public static void main(String[] args) {
Context context = new Context();
StartState startState = new StartState();
startState.doAction(context);
System.out.println(context.getState().toString());
StopState stopState = new StopState();
stopState.doAction(context);
System.out.println(context.getState().toString());
}
}
结果输出:
Spring State Machine示例:
状态机(状态模式的一种应用)在工作流或游戏等各种系统中有大量使用,如各种工作流引擎,它几乎是状态机的子集和实现,封装状态的变化规则。Spring状态机帮助开发者简化状态机的开发过程,让状态机结构更加层次化。
参考链接 https://cloud.tencent.com/developer/article/1487718
1、封装了转换规则。
2、枚举可能的状态,在枚举状态之前需要确定状态种类。
3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
1、状态模式的使用必然会增加系统类和对象的个数。
2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
3、状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。
后续:与策略模式的比较
同:
1、子类的使用:状态和策略模式都通过状态/策略的不同派生子类来更改具体实现。
2、模式类图:状态模式和策略模式之间最大的相似性之一是它们的类图,除了类名之外,它们看起来几乎相同。这两种模式都定义了状态/策略基类,子状态/子策略都继承基类。
3、两者都遵循开闭原则:状态模式的Context是对修改关闭的,即关于状态如何被访问和使用的逻辑是固定的。但是各个状态是开放的,也就是说,可以通过扩展可以添加更多的状态。类似地,策略模式的context是对修改关闭的,但是各个策略的子类是开放可扩展的。
异:
1、模式意图:策略模式的意图或目的是拥有一系列可互换的算法,这些算法可以根据context和/或客户需求进行选择。而状态模式的目的是管理对象的状态以及对象的行为,对象的行为会随着状态的变化而变化。
2、客户端对策略/状态的感知:在策略模式实现中,所选择的策略依赖于客户端,因此客户端知道使用的是哪种策略。而在状态模式实现中,客户端与context交互以对对象进行操作,但不决定选择哪种状态。对象本身似乎根据客户端通过context进行的交互来更改其状态类。
3、context的引用:状态模式中的每个状态都持有context的引用。但是,策略模式中每个策略并不持有context的引用。
4、状态/策略之间的关系:状态模式中的不同状态彼此相关,例如作为前一个或者后一个状态等。这是因为在状态之间像有限状态机有一个流动。然而,策略模式只是从多个可用策略中选择一个策略,策略之间没有后者/前者的关系。
5、怎样做/什么&何时做:多种策略定义了做某事的多种方式。而多个状态定义要做什么,并基于状态之间的关系定义何时做。