在变幻的时光中,状态如诗篇般细腻流转。
文章目录
一、可调节的灯光
场景假设:我们有一个电灯,它可以被打开和关闭。用户可以通过一个开关来改变电灯的状态。
java
/**
* 表示可以开关的灯的类。
*/
public class Light {
private String state; // 灯的当前状态,可能是"ON"或者"OFF"
/**
* 构造方法,初始化灯的状态为"OFF"。
*/
public Light() {
this.state = "OFF";
}
/**
* 开关灯的状态。
* 如果灯当前为"OFF",则将其改为"ON"并打印"灯已打开"。
* 如果灯当前为"ON",则将其改为"OFF"并打印"灯已关闭"。
*/
public void switchState() {
if ("OFF".equals(state)) {
state = "ON";
System.out.println("灯已打开");
} else {
state = "OFF";
System.out.println("灯已关闭");
}
}
}
上面的代码虽然能够实现需求,因为只有两种状态。但是,如果电灯有更多的状态,比如"调暗"、"调亮"、"闪烁"等,那么 switchState 方法就会变得非常复杂,充满了 if-else 语句。这将使代码难以阅读和维护。
二、状态模式
状态模式(State Pattern)是一种行为型
设计模式,它允许对象在其内部状态发生改变时改变其行为,使其看起来像是改变了其类。状态模式的关键思想是将对象的行为封装在不同的状态对象中,并且在状态转换时可以动态地改变对象的行为。
三、状态模式的核心组件
状态模式的核心组件包括以下几个角色:
- Context(上下文):上下文是拥有状态的对象。它定义了客户端感兴趣的接口,并且维护一个当前状态对象,这个状态对象定义了当前的状态和相应的行为。Context 可以通过状态对象来改变它的行为。
- State(状态):状态是一个接口或者抽象类,它封装了与 Context 的一个特定状态相关的行为。在 State 接口或者抽象类中定义了所有具体状态类所共享的方法,这些方法的实现将依赖于当前状态。通常,这些方法处理与状态相关的操作,如请求或者事件。
- ConcreteState(具体状态):具体状态类实现了 State 接口或者继承了 State 抽象类。每个具体状态类实现了与 Context 的一个状态相关的行为。例如,在电梯系统中,可能会有开门状态、关门状态、运行状态和停止状态等具体状态类。
这个类图展示了状态模式的核心组成部分:
- State 接口定义了 doAction(Context) 方法,表示所有具体状态类(OpenState 和 CloseState)需要实现的方法。
- OpenState 和 CloseState 类分别实现了 State 接口,并实现了 doAction(Context) 方法来处理具体的状态操作。
- Context 类包含一个状态接口类型的私有成员变量 state,通过 setState(State) 方法设置当前的状态,并通过 request() 方法执行当前状态的动作。
四、运用状态模式
场景假设:我们有一个电灯,它可以被打开和关闭。用户可以通过一个开关来改变电灯的状态。电灯有更多的状态,比如"调暗"、"调亮"、"闪烁"等。
-
定义状态接口:首先,我们需要定义一个状态接口,该接口声明了所有具体状态类需要实现的方法。在我们的例子中,我们可以定义一个 LightState 接口,该接口有一个 switchState 方法。
java// 定义状态接口 public interface LightState { // 声明改变状态的方法,接收一个 Light 对象作为参数 void switchState(Light light); }
-
创建具体状态类:然后,我们需要为每种状态创建一个具体的状态类。这些类需要实现状态接口,并实现接口中声明的方法。在我们的例子中,我们可以创建 OnState 和 OffState 类。
java// 创建具体状态类:打开状态 public class OnState implements LightState { @Override public void switchState(Light light) { // 改变 Light 对象的状态为 DimState light.setState(new DimState()); System.out.println("Light is dimmed"); } } // 创建具体状态类:关闭状态 public class OffState implements LightState { @Override public void switchState(Light light) { // 改变 Light 对象的状态为 OnState light.setState(new OnState()); System.out.println("Light is turned ON"); } } // 创建具体状态类:调暗状态 public class DimState implements LightState { @Override public void switchState(Light light) { // 改变 Light 对象的状态为 BlinkState light.setState(new BlinkState()); System.out.println("Light is blinking"); } } // 创建具体状态类:闪烁状态 public class BlinkState implements LightState { @Override public void switchState(Light light) { // 改变 Light 对象的状态为 OffState light.setState(new OffState()); System.out.println("Light is turned OFF"); } }
-
在上下文类中使用状态:最后,我们需要在上下文类中使用这些状态。上下文类维护一个对状态对象的引用,该引用可以在运行时更改。在我们的例子中,Light 类就是上下文类。
java// 创建上下文类:电灯 public class Light { // Light 对象维护一个对状态对象的引用 private LightState state; public Light() { // 初始状态为 OffState this.state = new OffState(); } // 设置 Light 对象的状态 public void setState(LightState state) { this.state = state; } // 切换 Light 对象的状态 public void switchState() { state.switchState(this); } }
-
客户端:通过客户端测试
javapublic class Client { public static void main(String[] args) { // 创建一个 Light 对象 Light light = new Light(); // 切换 Light 对象的状态 light.switchState(); // 打开电灯 light.switchState(); // 调暗电灯 light.switchState(); // 电灯开始闪烁 light.switchState(); // 关闭电灯 } }
五、状态模式的应用场景
状态模式在许多场景中都非常有用,特别是当一个对象的行为取决于其状态,并且它必须在运行时根据状态改变其行为时。以下是一些常见的应用场景:
- 用户界面(UI):在许多用户界面中,元素的行为会根据其状态(如禁用、选中、悬停等)而改变。状态模式可以帮助我们管理这些状态,并使状态转换的逻辑更加清晰。
- 游戏开发:在游戏开发中,角色的行为通常会根据其状态(如站立、跑动、跳跃、攻击等)而改变。使用状态模式,我们可以为每种状态创建一个状态类,使得代码更易于理解和维护。
- 工作流引擎:在工作流引擎中,任务的行为会根据其状态(如新建、进行中、已完成等)而改变。状态模式可以帮助我们管理这些状态,并使状态转换的逻辑更加清晰。
- 网络连接:网络连接的行为会根据其状态(如打开、关闭、等待等)而改变。状态模式可以帮助我们管理这些状态,并使状态转换的逻辑更加清晰。
六、小结
状态模式是一种优秀的设计模式,适用于那些对象行为会随着内部状态变化而变化的情况。它通过将对象的状态和行为分离,使得系统更加灵活、易于理解和扩展。