状态模式(state pattern):当一个对象内在状态改变时允许其改变行为,这个对象看起来像是改变了其类(也可以理解为把众多的if-else进行优化,将不同条件下的行为封装到一个类里,再给这些类一个父类来约束它们)。
类图及角色![在这里插入图片描述](https://img-blog.csdnimg.cn/20190619145051891.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3Rhbmd5dXpoaWRhbw==,size_16,color_FFFFFF,t_70)
环境(context)角色:定义客户程序需要的接口,客户程序通过它满足自己的需求。维护一个具体状态角色的实例,这个实例来决定当前的状态。
抽象状态角色(state):定义一个接口来封装与环境角色一个特定状态相关的行为。
具体状态(concrete state)角色:实现状态角色定义的接口。结构非常简单。
通过多态,可以动态地改变语境(context)对象的属性state的内容,从而使一个具体状态类指向另一个具体状态类,从而改变语境(context)对象的行为。
状态模式的优点
1、封装转化过程,也就是转化规则。
2、枚举可能的状态。
状态模式的实质:
- 使用状态模式前,客户端外界需要介入改变状态,客户端不用关注细节。
- 每个状态形成一个子类,只关心它的下一个可能状态,从而无形中形成了转化规则。
- 如果新状态的加入,只涉及它的前一个状态的修改和定义。
- 每个状态可以实现next()方法,指定下一个状态。或者设定状态的进入和退出行为。
状态模式的使用情况
- 类似开关的状态切换是很常见的存在,不只根据状态,也有根据属性。实际使用中也不用非要使用state模式,这样会产生很多子类,使简单的变复杂,关键取决于你的经验和对系统的理解深度,。
- 银行账户(状态的切换)、经典的TcpConnection(创建、侦听、关闭)、工具箱中挑选不同的工具。
- 状态模式允许客户端改变状态,状态机是自动改变状态,状态模式在工作流或者游戏系统中有大量使用,甚至是核心设计,状态模式是可以对整个游戏的架构起到核心作用。
//抽象状态角色
public abstract class State {
public abstract void handle(Context context);
}
//Context类,维护一个ConcreteState子类的实例,这个实例定义当前的状态
public class Context {
private State state;
public Context(State state) {
this.state = state;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public void request() {
this.state.handle(this);
}
}
//具体状态
class ConcreteStateA extends State {
@Override
public void handle(Context context) {
System.out.println("现在是在状态A");
context.setState(new ConcreteStateB());
}
}
class ConcreteStateB extends State {
@Override
public void handle(Context context) {
System.out.println("现在是在状态B");
context.setState(new ConcreteStateC());
}
}
class ConcreteStateC extends State {
@Override
public void handle(Context context) {
System.out.println("现在是在状态C");
context.setState(new ConcreteStateA());
}
}
//客户端,不断地发请求
public class Client {
public static void main(String[] args) {
Context context = new Context(new ConcreteStateA());
context.request();
context.request();
context.request();
context.request();
context.request();
}
}