前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >在 C#中使用状态模式简化代码

在 C#中使用状态模式简化代码

作者头像
郑子铭
发布2025-03-06 21:45:48
发布2025-03-06 21:45:48
5000
代码可运行
举报
运行总次数:0
代码可运行

如果你在处理处于多种状态的对象时,曾感觉被 if-else 语句或 switch 语句搞得晕头转向,那你并不孤单。这些条件判断会让代码变得一团糟——尤其是在管理对象历经不同阶段时的不同行为时更是如此。这时就该状态模式(State Pattern)登场了:它是以一种结构化、易于维护的方式来清晰管理基于状态的行为的方法。

今天,我们将以一个简单的订单处理系统为例,逐步讲解这个概念。我们会探讨如何在不堆砌 if-else 检查的情况下处理状态转换,以及状态模式如何帮助我们保持代码的整洁和可扩展性。

传统状态处理方式的问题:大量的条件判断语句

想象一个简单的订单处理系统,每个订单会经历以下几个阶段:

  • 待处理(Pending)
  • 已支付(Paid)
  • 已发货(Shipped)
  • 已送达(Delivered)
  • 已取消(Cancelled)

在管理每个状态时,我们可能希望:

  • 只对已支付的订单发货。
  • 只对已发货的订单进行派送。
  • 如果订单已送达或已取消,则阻止某些操作。

大多数人通过添加大量的 if-else 检查来处理这个问题。以下是在传统设置中它可能呈现的样子:

代码语言:javascript
代码运行次数:0
复制
public classOrder
{
    publicstring Status {get;set;}="Pending";

    publicvoidPay()
    {
        if(Status =="Pending")
        {
            Status ="Paid";
            Console.WriteLine("Order has been paid.");
        }
        else
        {
            Console.WriteLine("Cannot pay for order in current state: "+ Status);
        }
    }

    publicvoidShip()
    {
        if(Status =="Paid")
        {
            Status ="Shipped";
            Console.WriteLine("Order has been shipped.");
        }
        else
        {
            Console.WriteLine("Cannot ship order in current state: "+ Status);
        }
    }

    publicvoidDeliver()
    {
        if(Status =="Shipped")
        {
            Status ="Delivered";
            Console.WriteLine("Order has been delivered.");
        }
        else
        {
            Console.WriteLine("Cannot deliver order in current state: "+ Status);
        }
    }

    publicvoidCancel()
    {
        if(Status =="Pending"|| Status =="Paid")
        {
            Status ="Cancelled";
            Console.WriteLine("Order has been cancelled.");
        }
        else
        {
            Console.WriteLine("Cannot cancel order in current state: "+ Status);
        }
    }
}

这种方法有什么问题呢?

  • 条件过多:每个操作都有多个检查条件。随着状态数量的增加,这些检查条件会变得更长,也更难维护。
  • 逻辑分散:每个操作都必须了解所有可能的状态。这会把不同的逻辑混合在一处,使代码变得杂乱无章。
  • 修改困难:如果我们添加更多的状态或操作,就必须更新代码中所有的 if-else 代码块。

使用状态模式:管理状态的更好方法

状态模式允许对象根据其状态改变自身行为,方法是将每个状态的行为组织到各自的类中。通过这种方法:

  • 每个状态都有一个专门的类来处理其相关操作。
  • 我们可以在状态之间进行转换,而无需到处检查条件。
  • 我们能够保持代码整洁、易读且易于扩展。

实现状态模式

让我们逐步进行分解。

步骤 1:创建一个状态接口 我们将定义一个接口 IOrderState,其中包含订单类(Order 类)所需的每个操作的方法(例如 PayShipDeliverCancel)。

代码语言:javascript
代码运行次数:0
复制
public interface IOrderState
{
    void Pay(Order order);
    void Ship(Order order);
    void Deliver(Order order);
    void Cancel(Order order);
}

步骤 2:为每个状态创建类 现在,每个状态(如待处理、已支付、已发货等)都有自己的类,这些类实现 IOrderState 接口。每个类只处理在该状态下允许执行的操作。

例如,以下是待处理状态(PendingState)类可能的样子:

代码语言:javascript
代码运行次数:0
复制
public classPendingState:IOrderState
{
    publicvoidPay(Order order)
    {
        order.State =newPaidState();
        Console.WriteLine("Order has been paid.");
    }
    publicvoidShip(Order order)=> Console.WriteLine("Cannot ship a pending order.");
    publicvoidDeliver(Order order)=> Console.WriteLine("Cannot deliver a pending order.");
    publicvoidCancel(Order order)
    {
        order.State =newCancelledState();
        Console.WriteLine("Order has been cancelled.");
    }
}

以下是已支付状态(PaidState)类可能的样子:

代码语言:javascript
代码运行次数:0
复制
public classPaidState:IOrderState
{
    publicvoidPay(Order order)=> Console.WriteLine("Order is already paid.");
    publicvoidShip(Order order)
    {
        order.State =newShippedState();
        Console.WriteLine("Order has been shipped.");
    }
    publicvoidDeliver(Order order)=> Console.WriteLine("Cannot deliver a paid order.");
    publicvoidCancel(Order order)
    {
        order.State =newCancelledState();
        Console.WriteLine("Order has been cancelled.");
    }
}

每个状态只处理对其有意义的操作,这使得每个类都很小且易于理解。

步骤 3:将订单类定义为上下文 订单类(我们的上下文)维护当前状态。它不再进行 if-else 检查,而是将工作委托给当前状态对应的类来处理。

代码语言:javascript
代码运行次数:0
复制
public classOrder
{
    publicIOrderState State {get;set;}=newPendingState();

    publicvoidPay()=> State.Pay(this);
    publicvoidShip()=> State.Ship(this);
    publicvoidDeliver()=> State.Deliver(this);
    publicvoidCancel()=> State.Cancel(this);
}

现在,订单类只需将请求传递给它的状态对象,然后状态对象负责处理其余的事情。

测试基于状态的逻辑

让我们看看测试时它是什么样子的。

代码语言:javascript
代码运行次数:0
复制
var order = new Order();
order.Pay();      // 输出:Order has been paid.
order.Ship();     // 输出:Order has been shipped.
order.Deliver();  // 输出:Order has been delivered.
order.Cancel();   // 输出:Cannot cancel a delivered order.

没有 if-else 语句,也没有难以理解的条件判断——只有流畅的、基于状态的转换。

状态模式的优势

  • 代码条理清晰:每个状态类只处理特定状态的逻辑,所以代码更加整洁、有条理。
  • 可扩展性强:如果添加更多状态,只需添加新的类,而无需更改现有逻辑。
  • 可读性好:每个类都清晰地表明了在特定状态下可以做什么和不可以做什么,这使得代码更易于理解和调试。

何时使用基于状态的逻辑

在以下情况下,状态模式很有用:

  • 一个对象有多个状态,且每个状态都有不同的行为。
  • 根据状态执行不同操作时存在复杂的条件判断。
  • 可扩展性很重要——如果你计划添加更多状态或状态转换,这种方法将为你节省时间并减少烦恼。

使用状态模式可以使代码更易于理解、维护和扩展。我们不再处理混乱繁杂的条件判断,而是创建了一个每个状态都有明确职责的系统。这种结构有助于确保随着应用程序的发展,我们的代码依然保持整洁且易于修改。

代码语言:javascript
代码运行次数:0
复制
点击下方卡片关注DotNet NB
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-03-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DotNet NB 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 传统状态处理方式的问题:大量的条件判断语句
  • 使用状态模式:管理状态的更好方法
  • 实现状态模式
  • 测试基于状态的逻辑
  • 状态模式的优势
  • 何时使用基于状态的逻辑
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档