状态设计模式
简介
状态模式(State Pattern)也叫作状态机模式(State Machine Pattern),允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类,属于行为型设计模式。
通用模板
-
创建环境类角色:定义客户端需要的接口,内部维护一个当前状态实例,并负责具体状态的切换。
// 上下文环境类 public class Context { private IState currentState; // 默认状态A public Context() { this.currentState = new ConcreteStateA(); } // 提供改变状态方法 public void setState(IState state) { this.currentState = state; } // 执行 public void handle() { this.currentState.handle(this); } }
-
创建抽象状态角色:定义该状态下的行为,可以有一个或多个行为。
// 抽象状态接口 public interface IState { void handle(Context context); }
-
创建具体状态角色:具体实现该状态对应的行为,并且在需要的情况下进行状态切换。
// 具体状态类A public class ConcreteStateA implements IState { @Override public void handle(Context context) { // 必要时需要进行状态切换 System.out.println("StateA do action"); // 切换成状态B context.setState(new ConcreteStateB()); } }
// 具体状态类B public class ConcreteStateB implements IState { @Override public void handle(Context context) { // 必要时需要进行状态切换 System.out.println("StateB do action"); } }
模板测试
-
测试代码
public class Client { public static void main(String[] args) { Context context = new Context(); context.setState(new ConcreteStateA()); // 默认是状态A context.handle(); // 状态A之后会切换成状态B context.handle(); } }
-
测试结果
StateA do action StateB do action
应用场景
状态模式在生活场景中比较常见。例如,我们平时网购的订单状态变化。另外,我们平时坐电梯时电梯的状态变化。
在软件开发过程中,对于某一项操作,可能存在不同的情况。通常处理多情况的问题最直接的方式就是使用if…else或switch…case条件语句进行枚举。但是这种做法对于复杂状态的判断存在天然弊端:条件判断语句过于臃肿,可读性差,且不具备扩展性,维护难度也大。而如果转换思维,将这些不同状态独立起来,用各个不同的类进行表示,系统处于哪种情况,直接使用相应的状态类对象进行处理,消除了if…else、switch…case等冗余语句,代码更有层次性,并且具备良好的扩展力。
状态模式主要解决的就是控制一个对象状态的条件表达式过于复杂时的情况。通过把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。对象的行为依赖它的状态(属性),并且行为会随着它的状态改变而改变。状态模式主要适用于以下应用场景。
(1)行为随状态改变而改变的场景。
(2)一个操作中含有庞大的多分支结构,并且这些分支取决于对象的状态。
优点
(1)结构清晰:将状态独立为类,消除了冗余的if…else或switch…case语句,使代码更加简洁,提高了系统的可维护性。
(2)将状态转换显示化:通常对象内部都是使用数值类型来定义状态的,状态的切换通过赋值进行表现,不够直观;而使用状态类,当切换状态时,是以不同的类进行表示的,转换目的更加明确。 (3)状态类职责明确且具备扩展性。
缺点
(1)类膨胀:如果一个事物具备很多状态,则会造成状态类太多。
(2)状态模式的结构与实现都较为复杂,如果使用不当,将导致程序结构和代码的混乱。
(3)状态模式对开闭原则的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源码,否则无法切换到新增状态,而且修改某个状态类的行为也需要修改对应类的源码。
“生搬硬套”实战
场景描述
交通信号灯有三种状态:红灯(Red)、绿灯(Green)和黄灯(Yellow)。每种状态都有其特定的行为:红灯转绿灯、绿灯转黄灯、黄灯转红灯。
代码开发
-
创建环境类角色(这里指的是维护交通灯的环境类)
// 上下文类TrafficLight来维护当前状态,并提供改变状态的方法 public class TrafficLight { // 记录当前状态变量 private TrafficLightState currentLight; // 初始状态为红灯 public TrafficLight() { this.currentLight = new RedLight(); } // 设置当前状态 public void setLight(TrafficLightState light) { this.currentLight = light; } public void displayLight() { this.currentLight.displayLight(this); } }
-
创建抽象状态角色(这里指红绿黄三种状态接口)
// 状态接口,这个接口将定义所有可能的状态行为 public interface TrafficLightState { void displayLight(TrafficLight trafficLight); }
-
创建具体状态角色(这里是红、绿、黄三种具体状态类)
// 具体的红灯类 public class RedLight implements TrafficLightState { @Override public void displayLight(TrafficLight trafficLight) { System.out.println("当前是红灯!"); trafficLight.setLight(new GreenLight()); // 切换到绿灯状态 } }
// 具体的绿灯类 public class GreenLight implements TrafficLightState { @Override public void displayLight(TrafficLight trafficLight) { System.out.println("当前是绿灯!"); trafficLight.setLight(new YellowLight()); // 切换到黄灯状态 } }
// 具体的黄灯类 public class YellowLight implements TrafficLightState { @Override public void displayLight(TrafficLight trafficLight) { System.out.println("当前是黄灯!"); trafficLight.setLight(new RedLight()); // 切换回红灯状态 } }
至此,我们就通过“生搬硬套”状态模式的模板设计出一套请红绿灯切换案例,接下来我们进行测试:
- 代码测试
public class Test { public static void main(String[] args) { TrafficLight trafficLight = new TrafficLight(); for (int i = 0; i < 3; i++) { trafficLight.displayLight(); // 模拟交通灯变化 } } }
- 测试结果
当前是红灯! 当前是绿灯! 当前是黄灯!
总结
状态模式中类的行为是由状态决定的,在不同的状态下有不同的行为。其意图是让一个对象在其内部改变的时候,行为也随之改变。状态模式的核心是状态与行为绑定,不同的状态对应不同的行为。
原文地址:https://blog.csdn.net/Android_xue/article/details/142762253
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!