状态模式
定义
状态模式,又称状态对象模式(Pattern of Objects for States),状态模式是对象的行为模式。状态模式允许一个对象在其内部状态改变的时候改变其行为。这个对象看上去就像是改变了它的类一样。
角色
- 环境(Context)角色,也成上下文:定义客户端所感兴趣的接口,并且保留一个具体状态类的实例。这个具体状态类的实例给出此环境对象的现有状态。
- 抽象状态(State)角色:定义一个接口,用以封装环境(Context)对象的一个特定的状态所对应的行为。
- 具体状态(ConcreteState)角色:每一个具体状态类都实现了环境(Context)的一个状态所对应的行为。
示例
状态接口
public interface Status {
public void action();
}
状态1
public class Status1 implements Status {
private Context context;
public Status1(Context context) {
this.context = context;
}
@Override
public void action() {
System.out.println("状态1执行完毕,变成状态2");
context.setStatus(context.getStatus2());
context.execute();
}
}
状态2
public class Status2 implements Status {
private Context context;
public Status2(Context context) {
this.context = context;
}
@Override
public void action() {
System.out.println("状态2执行完毕,变成状态3");
context.setStatus(context.getStatus3());
context.execute();
}
}
状态3
public class Status3 implements Status {
private Context context;
public Status3(Context context) {
this.context = context;
}
@Override
public void action() {
System.out.println("状态3执行完毕,变回状态1");
context.setStatus(context.getStatus1());
}
}
全局对象(持有状态)
public class Context {
private Status1 status1 ;
private Status2 status2;
private Status3 status3;
private Status status;
public Context() {
//默认3种状态
status1 = new Status1(this);
status2 = new Status2(this);
status3 = new Status3(this);
//初始状态为状态1
status = status1;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public Status1 getStatus1() {
return status1;
}
public Status2 getStatus2() {
return status2;
}
public void execute(){
this.getStatus().action();
}
public Status3 getStatus3() {
return status3;
}
}
测试类
public class StatusTest {
public static void main(String[] args) {
Context context = new Context();
context.execute();
}
}
效果:
状态1执行完毕,变成状态2
状态2执行完毕,变成状态3
状态3执行完毕,变回状态1
分析
- 上图是比较粗略简单的状态,只是简单的体现了状态的转换,状态对象的封装等特点;
- 状态模式的主要优点在于封装了转换规则,并枚举可能的状态,它将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为,还可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数;其缺点在于使用状态模式会增加系统类和对象的个数,且状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱,对于可以切换状态的状态模式不满足“开闭原则”的要求。
与策略模式比较
相似之处
- 添加新的状态或策略都很容易,而且不需要修改使用它们的Context对象。
- 它们都让你的代码符合OCP原则。在状态模式和策略模式中,Context对象对修改是关闭的,添加新的状态或策略,都不需要修改Context。
- 正如状态模式中的Context会有初始状态一样,策略模式同样有默认策略。
- 状态模式以不同的状态封装不同的行为,而策略模式以不同的策略封装不同的行为。
- 它们都依赖子类去实现相关行为。
不同之处
- 策略模式封装了一组相关算法,它允许Client在运行时使用可互换的行为;状态模式帮助一个类在不同的状态显示不同的行为。(简单的来理解策略模式是在同一时刻不同的行为,状态模式是在不同时刻不同行为)
- 状态模式封装了对象的状态,而策略模式封装算法或策略。因为状态是跟对象密切相关的,它不能被重用;而通过从Context中分离出策略或算法,我们可以重用它们。(状态对象中会持有一个对象的引用,状态只能被该对象使用)
- 在状态模式中,每个状态通过持有Context的引用,来实现状态转移;但是每个策略都不持有Context的引用,它们只是被Context使用。(跟第二点类似)
- 状态模式中很好的定义了状态转移的次序;而策略模式并无此需要:Client可以自由的选择任何策略。(状态模式强调状态的改变)
- 最后但最重要的一个不同之处是,策略的改变由Client完成;而状态的改变,由Context或状态自己(具体策略在客户端中实现并使用,但是具体的状态在context执行某个方法或者其中一个方法执行完毕之后自动转换到另一个状态)
版权声明:本文为qq_30325833原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。