设计模式笔记

设计模式笔记(十二): 状态模式

2018-07-31  本文已影响13人  yeonon

我们写代码的时候,经常会用到逻辑判断if-else结构,特别是写业务代码的时候。之所以要用if-else结构是因为有某状态需要处理或者状态转移。例如Java的Thread类里定义了一个State枚举类,里面定义了线程的6个状态。这6个状态的变更并不是顺序变更的,其状态转移有时候是不确定的,所以如果不做特殊处理,仅仅使用If-lese来判断状态后做相应的处理,可能需要类似下面这样的代码:

//下面都是伪代码

if (state == NEW)
  handlerNEW()
else if (state == RUNNABLE)
  handlerRun()
......

例如如果状态是RUNNABLE,在处理状态的该状态的方法里,又需要若干个if-else来决定应该转移到哪个状态。即使程序员的逻辑非常严密,完整的处理了所有可能的状态。这样的写法也显得非常糟乱,而且如果现在加入一个新的状态,是不是又得费劲去处理这个新的状态。在阿里巴巴Java开发手册里有类似这样的一条建议:尽量少用if-else结构,如果非用使用,也不要超过三层。超过的话,应考虑使用状态设计模式。

状态模式

状态模式的类图大概是这样的:


状态模式类图(摘自书上)

State是接口,ConcreteStateA和ConcreteStateB是其实现类,Context可以看做是管理状态的类,里面包含了state的引用,可以通过改变这个引用的指向进行状态的转移。

下面是简单的代码实现:


//状态的抽象接口(可以有多个方法,看具体需求)
public interface State {

    void handle();
}

//状态的实现类
public class AState implements State {


    @Override
    public void handle() {
        System.out.println("handle A state");
    }
}

//状态的实现类
public class BState implements State {
    @Override
    public void handle() {
        System.out.println("handle B state");
    }
}

//状态的上下文,即管理状态的类
public class Context {

    private State state;

    public void request() {
        state.handle();
    }

    public void setState(State state) {
        this.state = state;
    }
}

//测试类
public class Main {

    public static void main(String[] args) {
        Context context = new Context();
        //设置初始状态
        context.setState(new AState());
        context.request();
        //假设发生了某一事件导致了状态的切换(由A状态切换到B状态)
        context.setState(new BState());
        context.request();
    }
}

上面的类图和代码实现都比较简单,关键就是将每一个具体的状态作为一个单独的类来处理,然后由一个管理状态的类来管理这些状态,例如状态的改变。

状态模式的特点

  1. 封装性较好。将对象的行为封装到单独的一个类中,隐藏类具体的实现逻辑,这样可以对状态做一个集中的管理(Context类),使得状态转移的逻辑较为清晰。
  2. 扩展性并不是很好,但是也有一定的扩展性。如果新增一个状态,可以直接实现State接口,实现相关逻辑即可。但是如果该状态和其他状态的联系较为紧密,那么可能会导致需要到原来的状态里去修改源码,有点不遵循“开闭原则”。

小结

现在可以给出状态模式的定义了:状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

本系列文章参考书籍是《Head First 设计模式》,文中代码示例出自书中。

上一篇 下一篇

猜你喜欢

热点阅读