状态模式是一种行为设计模式
,它允许对象在其内部状态发生变化时改变其行为。这种模式的核心思想是将状态封装在独立的对象中,而不是将状态逻辑散布在整个程序中。
用途
- 简化复杂的条件逻辑:通过将不同的状态封装在不同的类中,可以避免大量的条件语句,使代码更清晰、更易于维护。
- 提高可扩展性:添加新的状态或修改现有状态的行为时,只需修改或新增相应的状态类,而不需要修改现有的代码。
- 提高代码的复用性:状态对象可以在多个上下文对象之间共享,提高代码的复用性。
示例代码及类图
示例1:交通信号灯
public interface ILightState
{
void Handle(TrafficLight context);
}
public class RedLightState : ILightState
{
public void Handle(TrafficLight context)
{
Console.WriteLine("Red Light");
context.SetState(new GreenLightState());
}
}
public class GreenLightState : ILightState
{
public void Handle(TrafficLight context)
{
Console.WriteLine("Green Light");
context.SetState(new YellowLightState());
}
}
public class YellowLightState : ILightState
{
public void Handle(TrafficLight context)
{
Console.WriteLine("Yellow Light");
context.SetState(new RedLightState());
}
}
public class TrafficLight
{
private ILightState _state;
public TrafficLight(ILightState initialState)
{
_state = initialState;
}
public void ChangeLight()
{
_state.Handle(this);
}
public void SetState(ILightState state)
{
_state = state;
}
}
类图
示例2:订单状态管理
public interface IOrderState
{
void Handle(Order context);
}
public class PendingState : IOrderState
{
public void Handle(Order context)
{
Console.WriteLine("Order is pending");
context.SetState(new ProcessingState());
}
}
public class ProcessingState : IOrderState
{
public void Handle(Order context)
{
Console.WriteLine("Order is being processed");
context.SetState(new ShippedState());
}
}
public class ShippedState : IOrderState
{
public void Handle(Order context)
{
Console.WriteLine("Order has been shipped");
context.SetState(new DeliveredState());
}
}
public class DeliveredState : IOrderState
{
public void Handle(Order context)
{
Console.WriteLine("Order has been delivered");
}
}
public class Order
{
private IOrderState _state;
public Order(IOrderState initialState)
{
_state = initialState;
}
public void Process()
{
_state.Handle(this);
}
public void SetState(IOrderState state)
{
_state = state;
}
}
类图
示例3:游戏角色状态
public interface ICharacterState
{
void Handle(Character context);
}
public class IdleState : ICharacterState
{
public void Handle(Character context)
{
Console.WriteLine("Character is idle");
context.SetState(new WalkingState());
}
}
public class WalkingState : ICharacterState
{
public void Handle(Character context)
{
Console.WriteLine("Character is walking");
context.SetState(new RunningState());
}
}
public class RunningState : ICharacterState
{
public void Handle(Character context)
{
Console.WriteLine("Character is running");
context.SetState(new IdleState());
}
}
public class Character
{
private ICharacterState _state;
public Character(ICharacterState initialState)
{
_state = initialState;
}
public void Move()
{
_state.Handle(this);
}
public void SetState(ICharacterState state)
{
_state = state;
}
}
类图
代码解析
- 状态接口 (
IState
):定义了一个 Handle 方法,所有具体状态类都需要实现这个方法。 - 具体状态 (
StateA
和StateB
):实现了 IState 接口,具体实现了 Handle 方法。在处理完当前状态后,可以改变上下文的当前状态。 - 上下文类 (
Context
):维护一个对当前状态的引用,并提供一个方法 Request 来调用当前状态的 Handle 方法。上下文还提供了一个属性State
来改变当前状态,并在状态改变时输出相关信息。
优点
- 简化条件逻辑:通过将状态逻辑封装在不同的类中,减少了大量的条件语句,使代码更清晰、更易于维护。
- 提高可扩展性:添加新的状态或修改现有状态的行为时,只需修改或新增相应的状态类,而不需要修改现有的代码。
- 提高代码的复用性:状态对象可以在多个上下文对象之间共享,提高代码的复用性。
缺点
- 增加类的数量:每种状态都需要一个类,这可能会导致类的数量增多,增加系统的复杂性。
- 状态转换逻辑分散:状态转换的逻辑分布在不同的状态类中,有时可能难以追踪和理解。
- 过度设计:对于简单的状态转换,使用状态模式可能会显得过于复杂,增加不必要的开销。
总结
状态模式适用于需要管理多种状态和状态转换的场景,特别是在状态逻辑较为复杂的情况下。通过将状态逻辑封装在独立的类中,可以使代码更加模块化、易于维护和扩展。然而,在简单的情况下,使用状态模式可能会增加不必要的复杂性。