定义:
Allow an object to alter its behavior when its internal state changes.The object will appear to change its class.(当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其 类。)

状态模式通用类图
状态设计模式的核心思想是将状态相关的行为封装到状态类中,通过状态对象的切换来实现行为的改变。它避免了在一个类中使用大量的条件语句(如if - else或switch - case)来判断不同状态下的行为,而是将每个状态的行为逻辑分散到具体的状态类中。这样,当需要增加新状态或修改现有状态的行为时,只需新增或修改对应的状态类,符合开闭原则,提高了代码的可维护性和可扩展性。
角色:
状态模式包含以下几个核心角色:
1、环境类(Context)
环境类是拥有状态的对象,它维护一个当前状态的引用,并且提供操作状态的方法。环境类不直接实现与状态相关的行为,而是将行为委托给当前的状态对象。环境类充当状态对象和客户端之间的桥梁,客户端通过环境类间接访问状态对象的行为。
2、抽象状态类(State)
抽象状态类定义了一个接口,用于封装与环境类的一个状态相关的行为。它声明了所有具体状态类都必须实现的方法,这些方法对应了在该状态下环境类可能执行的操作。抽象状态类为具体状态类提供了统一的抽象,使得环境类可以以一致的方式与不同的状态对象交互。
3、具体状态类(Concrete State)
具体状态类是抽象状态类的实现类,每个具体状态类对应环境类的一个具体状态,负责实现该状态下环境类的行为逻辑。在具体状态类中,不仅实现了抽象状态类定义的方法,还可以维护该状态特有的数据或进行状态转换的逻辑判断。
4、客户端(Client)
客户端负责创建环境类和具体状态类的对象,并将初始状态设置到环境类中。客户端通过调用环境类的方法来触发状态相关的操作,但客户端通常不直接与具体状态类交互,而是由环境类和状态类协同完成状态管理和行为执行。
代码示例:
假设我们要实现一个电梯的状态管理系统,电梯有 "静止""上升""下降""故障" 四种状态,在不同状态下对楼层选择、开门关门等操作有不同的响应。
// 抽象状态类:电梯状态
java
public interface ElevatorState {
void selectFloor(int floor, ElevatorContext context);
void openDoor(ElevatorContext context);
void closeDoor(ElevatorContext context);
void emergencyStop(ElevatorContext context);
}
// 具体状态类:静止状态
java
public class IdleState implements ElevatorState {
@Override
public void selectFloor(int floor, ElevatorContext context) {
if (floor > context.getCurrentFloor()) {
context.setState(new UpState());
System.out.println("电梯开始上升,前往 " + floor + " 层");
} else if (floor < context.getCurrentFloor()) {
context.setState(new DownState());
System.out.println("电梯开始下降,前往 " + floor + " 层");
} else {
System.out.println("已在当前楼层");
}
}
@Override
public void openDoor(ElevatorContext context) {
System.out.println("电梯门打开");
}
@Override
public void closeDoor(ElevatorContext context) {
System.out.println("电梯门关闭");
}
@Override
public void emergencyStop(ElevatorContext context) {
context.setState(new FaultState());
System.out.println("电梯发生故障,紧急停止");
}
}
// 具体状态类:上升状态
java
public class UpState implements ElevatorState {
@Override
public void selectFloor(int floor, ElevatorContext context) {
if (floor > context.getCurrentFloor()) {
System.out.println("继续上升,前往 " + floor + " 层");
} else if (floor < context.getCurrentFloor()) {
context.setState(new DownState());
System.out.println("电梯改变方向,开始下降,前往 " + floor + " 层");
} else {
context.setState(new IdleState());
System.out.println("到达目标楼层,电梯停止");
}
}
@Override
public void openDoor(ElevatorContext context) {
context.setState(new IdleState());
System.out.println("电梯到达楼层,门打开");
}
@Override
public void closeDoor(ElevatorContext context) {
System.out.println("电梯门关闭,继续上升");
}
@Override
public void emergencyStop(ElevatorContext context) {
context.setState(new FaultState());
System.out.println("电梯发生故障,紧急停止");
}
}
// 具体状态类:下降状态
java
public class DownState implements ElevatorState {
@Override
public void selectFloor(int floor, ElevatorContext context) {
if (floor < context.getCurrentFloor()) {
System.out.println("继续下降,前往 " + floor + " 层");
} else if (floor > context.getCurrentFloor()) {
context.setState(new UpState());
System.out.println("电梯改变方向,开始上升,前往 " + floor + " 层");
} else {
context.setState(new IdleState());
System.out.println("到达目标楼层,电梯停止");
}
}
@Override
public void openDoor(ElevatorContext context) {
context.setState(new IdleState());
System.out.println("电梯到达楼层,门打开");
}
@Override
public void closeDoor(ElevatorContext context) {
System.out.println("电梯门关闭,继续下降");
}
@Override
public void emergencyStop(ElevatorContext context) {
context.setState(new FaultState());
System.out.println("电梯发生故障,紧急停止");
}
}
// 具体状态类:故障状态
java
public class FaultState implements ElevatorState {
@Override
public void selectFloor(int floor, ElevatorContext context) {
System.out.println("电梯故障,无法选择楼层");
}
@Override
public void openDoor(ElevatorContext context) {
System.out.println("电梯故障,尝试开门");
}
@Override
public void closeDoor(ElevatorContext context) {
System.out.println("电梯故障,无法关门");
}
@Override
public void emergencyStop(ElevatorContext context) {
System.out.println("电梯已处于故障状态");
}
}
// 环境类:电梯
java
public class ElevatorContext {
private ElevatorState state;
private int currentFloor;
public ElevatorContext() {
this.state = new IdleState();
this.currentFloor = 1;
}
public void setState(ElevatorState state) {
this.state = state;
}
public int getCurrentFloor() {
return currentFloor;
}
public void setCurrentFloor(int currentFloor) {
this.currentFloor = currentFloor;
}
public void selectFloor(int floor) {
state.selectFloor(floor, this);
}
public void openDoor() {
state.openDoor(this);
}
public void closeDoor() {
state.closeDoor(this);
}
public void emergencyStop() {
state.emergencyStop(this);
}
}
// 客户端代码
java
public class StatePatternClient {
public static void main(String[] args) {
ElevatorContext elevator = new ElevatorContext();
elevator.selectFloor(5);
elevator.openDoor();
elevator.closeDoor();
elevator.selectFloor(3);
elevator.emergencyStop();
}
}
优点 :
**1、提高代码可读性和可维护性:**将不同状态下的行为逻辑封装到具体状态类中,避免了大量条件语句的嵌套,使代码结构更加清晰。当需要修改某个状态的行为或增加新状态时,只需修改或新增对应的状态类,降低了代码维护的难度。
**2、符合开闭原则:**新增状态或修改现有状态行为时,无需修改环境类和其他状态类的代码,只需要创建新的具体状态类或修改已有状态类,满足了开闭原则,提高了系统的扩展性。
**3、便于状态管理和转换:**状态设计模式将状态转换逻辑封装在状态类中,每个状态类可以清晰地定义从当前状态到其他状态的转换条件和操作,使状态转换的管理更加直观和易于控制。
缺点:
**1、增加类的数量:**每个状态都需要一个对应的具体状态类,当状态数量较多时,会导致系统中类的数量显著增加,增加了代码的复杂性和理解难度。
**2、状态类之间的依赖关系:**在某些情况下,具体状态类之间可能存在复杂的依赖关系,特别是在涉及状态转换时,可能需要在多个状态类之间进行协调,增加了代码的维护成本。
**3、性能开销:**由于状态设计模式引入了多个状态类和对象之间的交互,相比于简单的条件语句实现,可能会产生一定的性能开销,尤其是在频繁进行状态切换和方法调用的场景中。
使用场景:
(一)对象行为依赖状态变化
当一个对象的行为会根据其内部状态的不同而发生显著变化,并且状态的数量较多,使用大量条件语句判断状态会使代码变得复杂且难以维护时,适合使用状态设计模式。例如,游戏角色在不同状态(如正常、中毒、无敌)下的行为差异很大,通过状态模式可以清晰地管理这些行为。
(二)状态转换逻辑复杂
如果对象的状态转换存在复杂的逻辑关系,不同状态之间的转换需要满足特定条件,状态设计模式可以将这些转换逻辑封装在具体状态类中,使状态转换的逻辑更加清晰易懂,便于维护和扩展。如自动售货机在 "有货""无货""投币""找零" 等状态间的转换控制。
(三)代码遵循开闭原则
当系统需要在不修改现有代码的基础上,方便地增加新的状态或修改现有状态的行为时,状态设计模式能够很好地满足这一需求。只需新增或修改具体状态类,而不会影响到环境类和其他状态类,符合开闭原则。
状态设计模式通过将对象的状态和行为进行封装与分离,为处理对象状态变化相关的问题提供了一种优雅且高效的解决方案。它在电梯控制、订单管理、游戏开发等众多领域有着广泛的应用,能够有效提高代码的可读性、可维护性和扩展性。然而,在使用状态设计模式时,也需要权衡其带来的类数量增加、依赖关系复杂和性能开销等问题。合理运用状态设计模式,能够让我们在面对复杂的状态管理需求时,构建出更加清晰、灵活和健壮的软件系统,使代码在状态的变迁中保持优雅与高效。