状态模式(二十二)

一、定义

    当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。
    怎么理解这句话呢,就比方水有不同的状态,气体、液体和固体,不同的状态拥有的行为和特征也不一致,例如水可以用来洗衣服,冰可以冷藏东西,水蒸气有遇冷会液化的行为,它们还是同一个对象,但是在不同的状态看起来像改变了其类。


二、角色

1. State 抽象状态角色

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

public abstract class State {
    //定义一个环境角色, 提供子类访问
    protected Context context;
    //设置环境角色
    public void setContext(Context _context){
        this.context = _context;
    }
    //行为1
    public abstract void handle1();
    //行为2
    public abstract void handle2();
}

2. ConcreteState 具体状态角色

    每一个具体状态必须完成两个职责:本状态的行为管理以及趋向状态处理,通俗地说,就是本状态下要做的事情,以及本状态如何过渡到其他状态。

public class ConcreteState1 extends State {
    @Override
    public void handle1() {
        //本状态下必须处理的逻辑
    }
    @Override
    public void handle2() {
        //设置当前状态为stat2
        super.context.setCurrentState(Context.STATE2);
        //过渡到state2状态, 由Context实现
        super.context.handle2();
    }
}
 
public class ConcreteState2 extends State {
    @Override
    public void handle1() {
        //设置当前状态为state1
        super.context.setCurrentState(Context.STATE1);
        //过渡到state1状态, 由Context实现
        super.context.handle1();
    }
    @Override
    public void handle2() {
        //本状态下必须处理的逻辑
    }
}

3. Context 环境角色

    定义客户端需要的接口,并且负责具体状态的切换。

public class Context {
    //定义状态
    public final static State STATE1 = new ConcreteState1();
    public final static State STATE2 = new ConcreteState2();
    //当前状态
    private State currentState;
    //获得当前状态
    public State getCurrentState() {
        return currentState;
    }
    //设置当前状态
    public void setCurrentState(State currentState) {
        this.currentState = currentState;
        //切换状态
        this.currentState.setContext(this);
    }
    //行为委托
    public void handle1() {
        this.currentState.handle1();
    }
    public void handle2() {
        this.currentState.handle2();
    }
}

环境角色有两个不成文的规定,即:

  1. 把状态对象声明为静态常量,有几个状态对象就声明几个静态常量。
  2. 环境角色具有状态抽象角色定义的所有行为,具体执行使用委托方式。

4. 场景模拟

public class Client {
    public static void main(String[] args) {
        //定义环境角色
        Context context = new Context();
        //初始化状态
        context.setCurrentState(new ConcreteState1());
        //行为执行
        context.handle1(); //执行State1的handle1
        context.handle2(); //执行State2的handle2
    }
}

三、优缺点

  • 优点:
  1. 结构清晰
    如果不是有状态模式,一个对象需要在不同状态执行不同方法或者拥有不同特性的话,你可能需要在大量的 switch...case 或者 if...else 语句来根据不同状态执行不同方法,代码看起来就很复杂了
  2. 遵循设计原则
    每一个状态都是一个子类,符合单一职责原则,且当需要增加一个状态时,也是可以增加一个子类,需要修改一个状态时,也是修改一个子类即可。
  3. 封装性好
    状态的变换放置在类的内部实现,外部调用就不需要知道类的内部是如何实现状态和行为的变换了。
  • 缺点:
  1. 子类多
    每一个状态都对应一个子类,如果完全使用状态模式就会有太多的子类,不好管理,需要在项目中权衡。
    为了避免子类过多,也可以在数据库中建立一个状态表,然后根据状态执行相应操作,也不会太复杂。


四、使用场景

  1. 对象的行为会随状态改变而改变
  2. 条件、分支判断语句的替代者


查看更多:设计模式分类以及六大设计原则

猜你喜欢

转载自blog.csdn.net/afei__/article/details/80766574