110、23种设计模式之状态模式(19/23)

一、定义

状态模式是一种行为型设计模式,它允许对象在内部状态改变时改变其行为,使得对象看起来好像修改了它的类。

核心思想:将对象的状态封装为独立的状态类,对象在不同状态下的行为由对应状态类实现,而非通过大量 if-else 或 switch 判断。

二、优缺点

优点:

  • 封装了状态的转换逻辑和不同状态下的行为,符合单一职责原则。

  • 避免了冗长的条件判断语句,代码可读性和可维护性更高。

  • 新增状态时只需扩展状态类,符合开闭原则。

  • 状态转换的逻辑清晰,便于跟踪和调试。

缺点:

  • 状态较多时,会导致状态类数量激增,增加系统复杂度。
  • 状态类之间可能存在依赖关系,增加了维护难度。

三、应用场景

  • 对象的行为依赖于其状态,且状态会频繁变化(如订单状态、支付状态)。
  • 代码中存在大量与状态相关的条件判断(if-else/switch),且难以维护。
  • 需要动态切换对象的行为,且不同行为之间有明确的状态边界(如游戏角色的 "存活""受伤""死亡" 状态)。

四、关键点总结

角色划分:

  • 环境类(Context):维护当前状态,负责状态切换,对外提供交互接口。
  • 抽象状态类(State):定义所有状态的公共行为接口。
  • 具体状态类(ConcreteState):实现抽象状态类,定义特定状态下的行为,并可触发状态转换。

核心逻辑

环境类通过委托当前状态对象处理请求,状态转换由具体状态类内部或环境类控制。

状态独立性

每个状态类专注于自身行为,降低耦合。

五、C# 代码示例

以 "订单状态流转" 为例,订单有 "待支付""已支付""已发货""已完成" 四种状态,每种状态下的行为(如支付、发货、确认收货)不同。

csharp 复制代码
using System;

// 抽象状态类:定义订单状态的行为接口
public abstract class OrderState
{
    protected OrderContext context;

    // 设置环境类引用(用于状态切换)
    public void SetContext(OrderContext context)
    {
        this.context = context;
    }

    // 抽象方法:支付订单
    public abstract void Pay();

    // 抽象方法:发货
    public abstract void Ship();

    // 抽象方法:确认收货
    public abstract void ConfirmReceipt();
}

// 具体状态:待支付
public class PendingPaymentState : OrderState
{
    public override void Pay()
    {
        Console.WriteLine("订单已支付,状态更新为【已支付】");
        // 切换状态为"已支付"
        context.State = new PaidState();
        context.State.SetContext(context);
    }

    public override void Ship()
    {
        Console.WriteLine("错误:订单未支付,无法发货");
    }

    public override void ConfirmReceipt()
    {
        Console.WriteLine("错误:订单未支付,无法确认收货");
    }
}

// 具体状态:已支付
public class PaidState : OrderState
{
    public override void Pay()
    {
        Console.WriteLine("错误:订单已支付,无需重复支付");
    }

    public override void Ship()
    {
        Console.WriteLine("订单已发货,状态更新为【已发货】");
        // 切换状态为"已发货"
        context.State = new ShippedState();
        context.State.SetContext(context);
    }

    public override void ConfirmReceipt()
    {
        Console.WriteLine("错误:订单未发货,无法确认收货");
    }
}

// 具体状态:已发货
public class ShippedState : OrderState
{
    public override void Pay()
    {
        Console.WriteLine("错误:订单已支付,无需重复支付");
    }

    public override void Ship()
    {
        Console.WriteLine("错误:订单已发货,无需重复发货");
    }

    public override void ConfirmReceipt()
    {
        Console.WriteLine("订单已确认收货,状态更新为【已完成】");
        // 切换状态为"已完成"
        context.State = new CompletedState();
        context.State.SetContext(context);
    }
}

// 具体状态:已完成
public class CompletedState : OrderState
{
    public override void Pay()
    {
        Console.WriteLine("错误:订单已完成,无需支付");
    }

    public override void Ship()
    {
        Console.WriteLine("错误:订单已完成,无需发货");
    }

    public override void ConfirmReceipt()
    {
        Console.WriteLine("错误:订单已完成,无需重复确认");
    }
}

// 环境类:订单上下文,维护当前状态并提供交互接口
public class OrderContext
{
    private OrderState _state;

    // 初始状态为"待支付"
    public OrderContext()
    {
        _state = new PendingPaymentState();
        _state.SetContext(this);
    }

    // 当前状态(用于状态切换)
    public OrderState State
    {
        get => _state;
        set => _state = value;
    }

    // 委托当前状态处理支付
    public void PayOrder()
    {
        _state.Pay();
    }

    // 委托当前状态处理发货
    public void ShipOrder()
    {
        _state.Ship();
    }

    // 委托当前状态处理确认收货
    public void ConfirmOrder()
    {
        _state.ConfirmReceipt();
    }
}

// 客户端调用
class Client
{
    static void Main(string[] args)
    {
        OrderContext order = new OrderContext();

        // 模拟订单流程
        order.PayOrder();    // 订单已支付,状态更新为【已支付】
        order.ShipOrder();   // 订单已发货,状态更新为【已发货】
        order.ConfirmOrder();// 订单已确认收货,状态更新为【已完成】
        order.PayOrder();    // 错误:订单已完成,无需支付
    }
}

输出结果:

csharp 复制代码
订单已支付,状态更新为【已支付】  
订单已发货,状态更新为【已发货】  
订单已确认收货,状态更新为【已完成】  
错误:订单已完成,无需支付  

说明:

  • 环境类 OrderContext 封装了订单状态的切换逻辑,客户端只需调用其公共方法(如 PayOrder)。
  • 每个具体状态类(如 PendingPaymentState)实现了对应状态下的行为,并在合适时机触发状态转换。
  • 新增状态(如 "已取消")时,只需添加新的具体状态类,无需修改现有代码,符合开闭原则。
相关推荐
杨充20 小时前
10.可测试性实战设计
设计模式·开源·代码规范
杨充20 小时前
9.重构十二式的实战
设计模式·开源·代码规范
杨充20 小时前
6.设计原则的全景图
设计模式·开源·全栈
杨充20 小时前
2.面向对象的特性
设计模式
杨充20 小时前
7.SOLID原则案例汇
设计模式·开源·全栈
杨充20 小时前
8.反模式与坏味道
设计模式·开源·代码规范
杨充20 小时前
3.接口vs抽象类比较
设计模式
咖啡八杯1 天前
文法、BNF与AST
java·设计模式·解释器模式·ast·文法
咖啡八杯1 天前
GoF设计模式——解释器模式
java·后端·spring·设计模式