今天我们来聊聊个红绿灯,我们知道有个口诀叫:
红灯停
绿灯行
黄灯亮了等一等
但这不是我们关注的重点,我们关注的点是我们红绿灯的状态!
一般是 绿灯 -> 黄灯-> 红灯 的顺序。
绿灯能且只能跑到黄灯
黄灯能且只能跑到红灯
红灯能且只能跑到绿灯
不过曾经深圳尝试改革,直接从绿灯
跳成了红灯
,消失一出,当时一片哗然,在试行了一段时间后,发现不妥就又恢复了。
所以现在我们使用红路灯这个案例,来看下我们怎么写一个基于状态模式的设计
代码实现
首先我们先抽象出一个基本的灯状态类。
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();
}
}
我们设置初始化我们的灯为绿色的,接着跳黄色和红色。
类图
后记
如果你要解决的问题需要状态,每个状态有特定的操作,不同状态可以做的事情不一样的话 ,可以使用这个状态模型。
大学时候曾经有学过状态机,这个状态模型和他挺类似的。
这里我们把每个状态都分割成一个类的做法,是为了避免如果是都放到了context里面去的话,我们执行每个操作的时候,都需要很多的判断语句,来看下当前的状态,以及该状态下可以做的操作。现在每个状态下只有一个操作还加单,如果每个状态下有很多操作,那么判断将变得很复杂,不容易维护。
不过这也带来了问题,当状态多的时候,这个状态类也会跟着变得很多,例如我们这里是三个,对应三种颜色的红绿灯。如果有三十多个,写起来还是挺累的。
另外这里我们的状态转换上,是通过state的子类来做的,我们的案例中使用的就是这样super.context.setLightState(Context.XXXLightState)
这带来的灵活性。不过如果当状态多了,同时设置后继续不恰当时候,可能存在循环。