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)实现了对应状态下的行为,并在合适时机触发状态转换。
  • 新增状态(如 "已取消")时,只需添加新的具体状态类,无需修改现有代码,符合开闭原则。
相关推荐
_院长大人_3 小时前
设计模式-单例模式
单例模式·设计模式
崎岖Qiu12 小时前
【设计模式笔记17】:单例模式1-模式分析
java·笔记·单例模式·设计模式
小雨青年14 小时前
Cursor 项目实战:AI播客策划助手(二)—— 多轮交互打磨播客文案的技术实现与实践
前端·人工智能·状态模式·交互
安冬的码畜日常17 小时前
【JUnit实战3_27】第十六章:用 JUnit 测试 Spring 应用:通过实战案例深入理解 IoC 原理
spring·观察者模式·设计模式·单元测试·ioc·依赖注入·junit5
她说彩礼65万19 小时前
C#设计模式 单例模式实现方式
单例模式·设计模式·c#
安冬的码畜日常1 天前
【JUnit实战3_28】第十七章:用 JUnit 5 实测 SpringBoot 项目
spring boot·功能测试·测试工具·设计模式·单元测试·junit5
围巾哥萧尘1 天前
TRAE Agent 歌曲创作助手构建与使用教程🧣
设计模式
superman超哥1 天前
仓颉语言中流式I/O的设计模式深度剖析
开发语言·后端·设计模式·仓颉
m0_748248021 天前
Spring设计模式刨根问底
java·spring·设计模式