文章目录
状态模式
状态模式 (State Pattern )又称为状态对象(Objects for States)模式,该模式允许一个对象在其内部状态改变时改变其行为。
状态模式就像一部智能的"剧情播放器",根据不同的"剧本"(状态)自动切换"演员"(行为),让系统"表演"出各种复杂且有序的行为。
定义
英文定义
The State Pattern allows an object to alter its behavior when its internal state changes. The object will appear to change its class.
直译
状态模式允许一个对象在其内部状态改变时改变其行为。这个对象看起来像是改变了它的类。
如何理解呢?
状态模式就像是一个智能的"状态机",它可以管理一个对象的多种状态,并根据当前状态来执行相应的行为。
比如,我们可以把一个电梯看作是一个对象,它有三种状态:停止、运行和故障。
当电梯处于不同的状态时,它的行为也会不同。
例如,
当电梯处于停止状态时,它不会移动;
当电梯处于运行状态时,它可以响应乘客的上下行请求;
当电梯出现故障时,它会停止运行并发出警报。
通过使用状态模式,我们可以将这些状态和对应的行为封装在单独的类中,使得代码更加清晰和易于维护。
同时,当需要添加新的状态或修改某个状态的行为时,我们只需要修改对应的状态类,而不需要修改其他部分的代码,这使得系统具有很好的扩展性和可维护性。
当控制一个对象状态的条件表达式过于复杂时,状态模式可以将这些复杂的判断逻辑转移到表示不同状态的一系列类中,从而简化判断逻辑。
状态模式的角色
Context(环境类)
也称为上下文,它定义了客户端所感兴趣的接口,并且维护一个具体状态对象的实例。这个实例定义了当前状态。
State(抽象状态类)
这是一个抽象类或接口,用以封装与Context的一个特定状态相关的行为。
ConcreteState(具体状态类)
这是实现了State接口的类,每一个类实现了一个与Context的一个状态相关的行为。
类图
代码示例
java
package com.polaris.designpattern.list3.behavioral.pattern10.state.classicdemo;
// 抽象状态类
interface State {
void handleRequest(Context context);
}
// 具体状态类A
class StateA implements State {
@Override
public void handleRequest(Context context) {
System.out.println("StateA handling request");
// 假设在StateA处理请求后,无条件地转移到StateB
context.setState(new StateB());
}
}
// 具体状态类B
class StateB implements State {
@Override
public void handleRequest(Context context) {
System.out.println("StateB handling request");
// 假设在StateB处理请求后,根据某个条件判断是否转回StateA
if (someConditionToCheck()) { // 这是一个假设的条件检查方法
context.setState(new StateA());
System.out.println("State changed to A");
} else {
System.out.println("Remaining in State B");
}
}
// 假设的条件检查方法
private boolean someConditionToCheck() {
// 这里可以添加你的条件逻辑
// 例如,可以检查某个变量的值,或者模拟用户输入等
// 这里我们简单地返回一个固定值作为示例
return Math.random() < 0.5; // 50% 的概率返回 true
}
}
// 环境类
class Context {
private State state;
public Context() {
// 初始状态设置为StateA
this.state = new StateA();
}
public void setState(State state) {
this.state = state;
}
public void request() {
// 委托给当前状态对象处理请求
state.handleRequest(this);
}
// Getter方法用于调试或日志记录(可选)
public State getState() {
return state;
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Context context = new Context();
// 客户端发送请求给Context
context.request(); // 输出 "StateA handling request",并转移到StateB
// 假设这里有一些业务逻辑,但这里没有额外的代码
// 再次发送请求以展示可能的状态变化
context.request(); // 输出 "StateB handling request",并根据条件判断是否转回StateA
// 第三次发送请求,以展示状态可能继续变化或保持不变
context.request(); // 输出将取决于StateB中的条件判断
// (可选)打印当前状态用于调试或日志记录
System.out.println("Current state: " + context.getState().getClass().getSimpleName());
}
}
/* Output:
StateA handling request
StateB handling request
State changed to A
StateA handling request
Current state: StateB
*///~
在上面的示例中,
Context
类代表了一个对象,它的行为可能会根据当前的状态(State
)而变化。每个ConcreteState
(这里是StateA
和StateB
)都定义了在该状态下如何处理请求。当Context
收到一个请求时,它会将请求委托给当前的状态对象去处理。状态对象在处理请求时,可能会改变Context
的状态。
状态模式的应用
状态模式是一种行为型设计模式,它允许一个对象在其内部状态改变时改变其行为。简单来说,就是当某个对象有多种状态,并且不同状态下有不同的行为时,我们可以使用状态模式来管理这些状态和对应的行为。
优点
- 封装了状态的转换规则:状态模式将状态的转换逻辑封装在状态类中,使得代码更加清晰和易于管理。
- 简化条件语句:避免了使用大量的条件语句来判断对象的状态和行为,使得代码更加简洁和易于维护。
- 可维护性高:当需要添加新的状态或修改某个状态的行为时,只需要修改对应的状态类,而不需要修改其他部分的代码,符合开闭原则。
- 扩展性好:状态模式允许新的状态类很容易地加入到系统中,使得系统具有很好的扩展性。
缺点
- 增加系统复杂性:使用状态模式会增加系统中类和对象的个数,使得系统结构变得复杂。
- 对开闭原则的支持不足:虽然状态模式在一定程度上符合开闭原则,但当需要添加新的状态时,可能需要修改状态转换的代码,这可能会破坏开闭原则。
- 使用不当可能导致代码混乱:如果状态模式和具体业务逻辑结合不当,可能会导致代码结构混乱,增加维护难度。
使用场景
- 对象的行为取决于它的状态:当对象的行为会根据其内部状态的不同而发生变化时,可以使用状态模式。
- 状态转换逻辑复杂:当对象的状态转换逻辑非常复杂时,使用状态模式可以将这些逻辑封装在状态类中,使得代码更加清晰和易于维护。
- 避免使用大量的条件语句 :++当代码中使用了大量的条件语句来判断对象的状态和行为时,可以考虑使用状态模式来简化代码。++