设计模式系列18---有状态的状态模式

enter image description here

今天我们来聊聊个红绿灯,我们知道有个口诀叫:

红灯停
绿灯行
黄灯亮了等一等

但这不是我们关注的重点,我们关注的点是我们红绿灯的状态!

一般是 绿灯 -> 黄灯-> 红灯 的顺序。

绿灯能且只能跑到黄灯
黄灯能且只能跑到红灯
红灯能且只能跑到绿灯

不过曾经深圳尝试改革,直接从绿灯跳成了红灯,消失一出,当时一片哗然,在试行了一段时间后,发现不妥就又恢复了。

所以现在我们使用红路灯这个案例,来看下我们怎么写一个基于状态模式的设计

代码实现

首先我们先抽象出一个基本的灯状态类。

public abstract class LightState {

    protected Context context;

    public void setContext(Context  mContext){
        this.context=mContext;
    }

    public abstract void toRed();
    public abstract void toGreen();
    public abstract void toOrange();

}

我们的每个灯有三个可以换的颜色,分别是变绿toGreen,变红toRed 和变黄toOrange。对于这里提到的context,这个可以看成我们的总控制台,负责记录当前的状态信息和控制状态。

接着我们来看下我们的绿灯

public class GreenLightState extends LightState {

    @Override
    public void toGreen() {
        System.out.println(" green light");
    }

    @Override
    public void toOrange() {
        this.context.setLightState(Context.orangeLightState);
        this.context.toOrange();
    }

    @Override
    public void toRed() {
        throw new UnsupportedOperationException();
    }
}

绿灯能做的就是变成黄色的,对于变成红色是错误的操作,我们抛出异常。

接着我们的黄色灯也类似的操作

public class OrangeLightState extends LightState {

    @Override
    public void toRed() {
        this.context.setLightState(Context.redLightState);
        this.context.toRed();
    }

    @Override
    public void toOrange() {
        System.out.println("orange light");

    }

    @Override
    public void toGreen() {
        throw new UnsupportedOperationException();
    }
}

最后是我们的红灯。

public class RedLightState extends LightState {

    @Override
    public void toRed() {
        System.out.println("red state");
    }

    @Override
    public void toGreen() {
        super.context.setLightState(Context.greedLightState);
        super.context.toGreen();
    }

    @Override
    public void toOrange() {
        throw new UnsupportedOperationException();
    }
}

在写好了这些,我们是时候祭出我们的Context控制台了

public class Context {

    public final static RedLightState redLightState = new RedLightState();
    public final static GreenLightState greedLightState = new GreenLightState();
    public final static OrangeLightState orangeLightState = new OrangeLightState();

    private LightState lightState;

    public LightState getLightState() {
        return lightState;
    }

    public void setLightState(LightState lightState) {
        this.lightState = lightState;
        this.lightState.setContext(this);
    }

    public void toGreen() {
        this.lightState.toGreen();
    }

    public void toRed() {
        this.lightState.toRed();
    }

    public void toOrange() {
        this.lightState.toOrange();
    }
}

我们的控制台负责的就是管理我们的灯的状态。

看下我们的实际案例

public class Client {
    public static void main(String[] args) {

        Context context=new Context();
        context.setLightState(Context.greedLightState);

        context.toOrange();
        context.toRed();
    }
}

我们设置初始化我们的灯为绿色的,接着跳黄色和红色。

类图

enter image description here

后记

如果你要解决的问题需要状态,每个状态有特定的操作,不同状态可以做的事情不一样的话 ,可以使用这个状态模型。
大学时候曾经有学过状态机,这个状态模型和他挺类似的。

这里我们把每个状态都分割成一个类的做法,是为了避免如果是都放到了context里面去的话,我们执行每个操作的时候,都需要很多的判断语句,来看下当前的状态,以及该状态下可以做的操作。现在每个状态下只有一个操作还加单,如果每个状态下有很多操作,那么判断将变得很复杂,不容易维护。
不过这也带来了问题,当状态多的时候,这个状态类也会跟着变得很多,例如我们这里是三个,对应三种颜色的红绿灯。如果有三十多个,写起来还是挺累的。

另外这里我们的状态转换上,是通过state的子类来做的,我们的案例中使用的就是这样super.context.setLightState(Context.XXXLightState)
这带来的灵活性。不过如果当状态多了,同时设置后继续不恰当时候,可能存在循环。

热评文章