【设计模式-4.6】行为型——状态模式
说明:本文介绍行为型设计模式之一的状态模式
定义
状态模式(State Pattern)也叫作状态机模式(State Machine Pattern),允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类,属于行为型设计模式。(引自《设计模式就该这样学》P348)
“对象看起来好像修改了它的类”,指对象的状态发生改变后,与之对应的行为也会发生改变(当然,这取决于你的业务逻辑)。
状态模式中类的行为是由状态决定的,在不同的状态下有不同的行为。其意图是让一个对象在其内部改变的时候,行为也随之改变。状态模式的核心是状态与行为绑定,不同的状态对应不同的行为。(引自《设计模式就该这样学》P348)
这段讲的很好。
灯的状态
灯的状态简单来分,只有两种,开的和熄灭的,所以更换灯的状态,代码写出来,很简单,如下:
/** * 灯开关 */ public class Switcher { /** * 灯状态 * false:熄灯 * true:开灯 */ private boolean state = false; /** * 使开灯 */ public void switchOn() { state = true; System.out.println("开灯"); } /** * 使熄灯 */ public void switchOff() { state = false; System.out.println("熄灯"); } }
作为程序员的严谨,需要考虑到灯在开启的时候,再调用开启方法的情况和灯在熄灭的时候,再调用熄灭方法的情况,如下:
/** * 灯开关-Plus */ public class SwitcherPlus { /** * 灯状态 * false:熄灯 * true:开灯 */ private boolean state = false; public void switchOn() { // 如果是熄灯 if (!state) { state = true; System.out.println("开灯"); } else { System.out.println("灯已经是开灯状态,无需重复开灯"); } } public void switchOff() { // 如果是开灯 if (state) { state = false; System.out.println("熄灯"); } else { System.out.println("灯已经是熄灭状态,无需重复熄灯"); } } }
代码变得复杂起来了,以上仅是一个对象,两种状态的情况,用if-else还能应付。如果是多个状态,例如交通信号灯,有红黄绿三个状态,绿灯变红灯,红灯变黄灯,黄灯变绿灯,代码如下:
/** * 交通信号灯 */ public class TrafficLight { /** * 信号灯状态,默认红 * 红灯转绿灯,绿灯转黄灯,黄灯转红灯 */ private String state = "红"; /** * 切换到绿灯 */ public void switchToGreen() { if ("绿".equals(state)) { System.out.println("已是绿灯,无需切换。。。"); } else if ("红".equals(state)) { System.out.println("成功切换到绿灯~~~"); } else if ("黄".equals(state)) { System.out.println("黄灯不能切换到绿灯!!!"); } } /** * 切换到黄灯 */ public void switchToYellow() { if ("绿".equals(state)) { System.out.println("成功切换到黄灯~~~"); } else if ("红".equals(state)) { System.out.println("红灯不能切换到黄灯!!!"); } else if ("黄".equals(state)) { System.out.println("已是黄灯,无需切换。。。"); } } /** * 切换到红灯 */ public void switchToRed() { if ("绿".equals(state)) { System.out.println("绿灯不能切换到红灯!!!"); } else if ("红".equals(state)) { System.out.println("已是红灯,无需切换。。。"); } else if ("黄".equals(state)) { System.out.println("成功切换到红灯~~~"); } } }
多层的if-else,代码显得臃肿,难以维护,后续涉及修改也会频繁改动这个类。
状态模式
使用状态模式,将方法、状态抽出来,如下:
(状态接口,State)
/** * 状态 */ public interface State { /** * 切换到绿灯 */ void switchToGreen(TrafficLight trafficLight); /** * 切换到黄灯 */ void switchToYellow(TrafficLight trafficLight); /** * 切换到红灯 */ void switchToRed(TrafficLight trafficLight); }
(红灯实现类,Red,注意切换成功后修改状态)
/** * 红灯 */ public class Red implements State { @Override public void switchToGreen(TrafficLight trafficLight) { trafficLight.setState(new Green()); System.out.println("成功切换到绿灯~~~"); } @Override public void switchToYellow(TrafficLight trafficLight) { System.out.println("红灯不能切换到黄灯!!!"); } @Override public void switchToRed(TrafficLight trafficLight) { System.out.println("已是红灯,无需切换。。。"); } }
(绿灯实现类,Green,注意切换成功后修改状态)
/** * 绿灯 */ public class Green implements State { @Override public void switchToGreen(TrafficLight trafficLight) { System.out.println("已是绿灯,无需切换。。。"); } @Override public void switchToYellow(TrafficLight trafficLight) { trafficLight.setState(new Yellow()); System.out.println("成功切换到黄灯~~~"); } @Override public void switchToRed(TrafficLight trafficLight) { System.out.println("绿灯不能切换到红灯!!!"); } }
(黄灯实现类,Yellow,注意切换成功后修改状态)
/** * 黄灯 */ public class Yellow implements State { @Override public void switchToGreen(TrafficLight trafficLight) { System.out.println("黄灯不能切换到绿灯!!!"); } @Override public void switchToYellow(TrafficLight trafficLight) { System.out.println("已是黄灯,无需切换。。。"); } @Override public void switchToRed(TrafficLight trafficLight) { trafficLight.setState(new Red()); System.out.println("成功切换到红灯~~~"); } }
(信号灯类,TrafficLight,只需调用抽象方法即可)
/** * 交通信号灯 */ public class TrafficLight { /** * 默认状态:红灯 */ State state = new Red(); /** * 设置灯状态 */ public void setState(State state) { this.state = state; } /** * 切换到绿灯 */ public void switchToGreen() { state.switchToGreen(this); } /** * 切换到黄灯 */ public void switchToYellow() { state.switchToYellow(this); } /** * 切换到红灯 */ public void switchToRed() { state.switchToRed(this); } }
(客户端,Client)
public class Client { public static void main(String[] args) { TrafficLight trafficLight = new TrafficLight(); trafficLight.switchToGreen(); trafficLight.switchToYellow(); trafficLight.switchToRed(); } }
执行如下
看下来,使用状态模式,减少了单个类使用大量if-else分支处理复杂逻辑的代码,使代码便于维护,后续还有其他状态,如粉灯、蓝灯,只需要增加对应的类,对应的抽象方法即可,不需要更改原来的代码。
综合来看,状态模式,将原本的代码(code)层面上的结构化,转为了类(class)层面上的结构化,这也是其他设计模式的大体思想。
使用场景
在《设计模式就该这样学》(P349)这本书中,提到状态模式适用于以下场景:
(1)行为随状态改变而改变的场景;
(2)一个操作中含有庞大的多分支结构,并且这些分支取决于对象的状态;
总结
本文介绍了行为型设计模式中的状态模式,参考《设计模式就该这样学》、《秒懂设计模式》两书,交通信号灯场景是《秒懂设计模式》中的举例。