努力保头发的打工人
努力保头发的打工人
发布于 2021-01-24 / 71 阅读 / 0 评论 / 0 点赞

状态模式

1 概述

定义 当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。

状态模式的核心是封装,状态的变更引起了行为的变更,从外部看起来就好像这个对象对应的类发生了改变一样。通用类图如下:

状态模式类图.png

  • state 抽象状态角色:接口或抽象类,负责对象状态的定义,并且封装环境以实现状态切换。

  • concretestate 具体状态角色:负责本状态的行为和趋向状态的过渡处理

  • context 环境角色:定义客户端需要的接口,并负责具体状态的切换

2 代码示例

定义状态抽象类和具体状态类

/**
 * @author chiangtaol
 * @date 2020-12-09
 * @describe 状态抽象类
 */
public abstract class StateAbstract {
​
    /** 环境角色,提供给子类访问*/
    protected Context context;
​
    public void setContext(Context context){
        this.context = context;
    }
​
    /** 行为1*/
    public abstract void handler1();
    /** 行为2*/
    public abstract void handler2();
    /** 行为3*/
    public abstract void handler3();
}
​
/**
 * @author chiangtaol
 * @date 2020-12-09
 * @describe 状态1
 */
public class State1 extends StateAbstract{
    /**
     * 行为1
     */
    @Override
    public void handler1() {
        System.out.println("行为1触发...");
    }
​
    /**
     * 行为2
     */
    @Override
    public void handler2() {
        // 设置当前状态为2
        super.context.setCurrentState(Context.STATE_2);
        // 交由context去执行委托给具体的实现类
        super.context.handle2();
    }
​
    /**
     * 行为3
     */
    @Override
    public void handler3() {
        // 规定不能由1-3
        System.out.println("违规操作:不能1状态下执行行为3");
    }
}
​
/**
 * @author chiangtaol
 * @date 2020-12-09
 * @describe 状态2
 */
public class State2 extends StateAbstract{
    /**
     * 行为1
     */
    @Override
    public void handler1() {
        // 规定不能由2-1
        System.out.println("违规操作:不能2状态下执行行为1");
    }
​
    /**
     * 行为2
     */
    @Override
    public void handler2() {
        System.out.println("行为2触发...");
    }
​
    /**
     * 行为3
     */
    @Override
    public void handler3() {
        // 修改状态
        super.context.setCurrentState(Context.STATE_3);
        // 交给context去执行,委托给对应的实现类
        super.context.handle3();
    }
}
​
/**
 * @author chiangtaol
 * @date 2020-12-09
 * @describe 状态3
 */
public class State3 extends StateAbstract{
    /**
     * 行为1
     */
    @Override
    public void handler1() {
        // 改变状态
        super.context.setCurrentState(Context.STATE_1);
        super.context.handle1();
    }
​
    /**
     * 行为2
     */
    @Override
    public void handler2() {
        // 规定不能由3-2
        System.out.println("违规操作:不能3状态下执行行为2");
    }
​
    /**
     * 行为3
     */
    @Override
    public void handler3() {
        System.out.println("行为3触发...");
    }
}

定义场景类

/**
 * @author chiangtaol
 * @date 2020-12-09
 * @describe 环境角色
 */
public class Context {
​
    public final static StateAbstract STATE_1 = new State1();
​
    public final static StateAbstract STATE_2 = new State2();
​
    public final static StateAbstract STATE_3 = new State3();
​
    /**
     * 当前状态
     */
    private StateAbstract currentState;
​
    public StateAbstract getCurrentState() {
        return currentState;
    }
​
    public void setCurrentState(StateAbstract currentState) {
        this.currentState = currentState;
        // 切换状态
        this.currentState.setContext(this);
    }
​
    // 声明行为,具体执行交给状态实现类
    public void handle1() {
        this.currentState.handler1();
    }
​
    public void handle2() {
        this.currentState.handler2();
    }
​
    public void handle3() {
        this.currentState.handler3();
    }
​
}

测试代码

@Test
public void test(){
    //初始化环境角色
    Context context = new Context();
    //设置初始状态
    context.setCurrentState(Context.STATE_1);
​
    context.handle3();
    context.handle1();
    context.handle2();
    context.handle3();
​
}
//结果
//违规操作:不能1状态下执行行为3
//行为1触发...
//行为2触发...
//行为3触发...

3 优缺点

3.1 优点
  • 结构清晰

  • 遵循设计原则,每个状态都是一个子类

  • 封装性很好,状态的变换放到类内部实现,外部调用不用知道如何实现

3.2 缺点

状态过多会引起类膨胀的问题

4 使用场景

  • 行为会随着状态改变而改变的场景

  • 条件、分支判断语句替换

  • 对象状态改变时行为受到约束的情况下使用