如何将 switch 语句重构为灵活的有限状态机

How To Refactor Switch Statement To Flexible Finite State Machine

在制造环境中,对于特定过程,有相当简单的 C# Winforms 桌面应用程序涉及无限循环中基于枚举的状态机 运行,遵循类似于以下的结构(状态名称保持通用举个例子)。

switch(state):

    case STATE0:
       // code (ui update, business logic, and/or database/device communication)
       if (...)
          state = STATE1; // goes to next state

       break;

    case STATE1:
       // code (ui update, business logic, and/or database/device communication)
       if(...)
          state = STATE2; // goes to next state

       break;

    case STATE2:
       // code (ui update, business logic, and/or database/device communication)
       if(...)
          state = STATE1; // goes back to STATE1
    
       else if (...)
          state = STATE3; // goes to next state

       break;
    
    case STATE3:
       // code (ui update, business logic, and/or database/device communication)
       if (...)
          state = STATE0; // goes back to STATE0

       break;

有很多产品都经过这个过程。产品中有许多状态几乎完全相同(例如 state0)。但是特定于产品的逻辑中,状态在不同产品之间略有不同。

有没有办法将上面的 switch 语句重构为更简洁、更灵活的有限状态机,它可以解释状态内的变化?

如果你有多个状态,需要根据状态改变行为,那么我们可以使用策略模式结合工厂模式。

首先,我们需要声明状态:

public enum State
{
    State_1,
    State_2,
    State_3,
    State_4
}

然后根据状态我们需要选择一些行为。我们可以将行为放在 class 中。我们称之为产品。所以我们需要创建一些抽象class,并将所有重复的逻辑放在这个抽象class中。然后,如果某些 classes 的行为不同或者我们想要添加新的行为,那么我们将创建派生的 classes。通过添加新的 classes 我们保持 Open Closed principle.

public abstract class Product
{
    public string Name { get; set; }

    public decimal Price { get; set; }


    public string TheSameBehaviorForAllProducts() 
    {
        return "TheSameHehaviorForAllProducts";
    }


    public virtual string BehaviorThatCanBeOverridenInDerivedClasses()
    {
        return "TheSameHehaviorForAllProducts";
    }
}

Product 的 class 派生:

public class Product_A : Product
{
    public override string BehaviorThatCanBeOverridenInDerivedClasses()
    {
        return "New Behavior Here";
    }
}

public class Product_B : Product
{
    public override string BehaviorThatCanBeOverridenInDerivedClasses()
    {
        return "New Behavior Here";
    }
}

public class Product_C : Product
{
    public override string BehaviorThatCanBeOverridenInDerivedClasses()
    {
        return "New Behavior Here";
    }
}

然后我们可以创建一个类似映射器的东西,将 State 映射到 Product。它也可以被认为是工厂模式:

public class StateToProduct 
{
    public Dictionary<State, Product> ProductByState = new()
        {
            { State.A, new Product_A() },
            { State.B, new Product_B() },
            { State.C, new Product_C() }
        };
}

和我们的状态机:

public class StateMachine
{
    // Here your logic to get state
    public State GetState() 
    {
        return State.A;
    }
}

然后我们可以运行这样的大系统:

public class SomeBigSystem
{
    public void Run()
    {
        StateMachine stateMachine = new();
        StateToProduct stateToProduct = new();
        Product product = stateToProduct.ProductByState[stateMachine.GetState()];

        // executing some business logic
        product.BehaviorThatCanBeOverridenInDerivedClasses();
    }
}   

因此,我们创建了可测试的简单 classes,并且我们在此处使用了策略模式。

我强烈建议您阅读有关 SOLID and techniques of refactoring

的内容