You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确实现表单状态的状态机模式?现有实现存疑求指导

表单状态机模式的改进方案

你的现有实现没感受到状态机的优势,核心问题是职责边界模糊、状态跳转逻辑耦合严重、动作触发不清晰,以下是针对性的改进思路和代码示例:

现有实现的核心问题

  • 状态类既判断业务规则又处理跳转,还重复设置枚举值与状态对象,职责混乱
  • 状态之间互相依赖(比如一个状态类直接实例化另一个状态类),新增/修改状态时要改多个类,违反开闭原则
  • 初始状态硬编码为Draft,没考虑表单从数据库加载时已有状态的场景
  • 用一个笼统的HandleStateTransition处理所有跳转,无法区分用户的具体动作(提交、审批、拒绝)

改进思路

  1. 明确动作与状态的对应关系:状态机的触发应该是用户的具体动作(提交表单、经理审批、技术审批等),而非状态自己主动跳转
  2. 状态类只负责自身允许的动作:每个状态类只实现当前状态下能响应的动作,以及对应的状态转换逻辑
  3. 分离状态枚举与状态类的映射:用字典维护枚举到状态类的映射,避免硬编码
  4. 业务规则集中管理:把金额、表单类型这类判断逻辑集中在对应动作的处理中,避免在多个状态类中重复编写

改进后的代码实现

1. 修正状态机服务类(FormStateService)

public class FormStateService
{
    private readonly Dictionary<State, FormState> _stateMap;
    private FormState _currentState;
    private readonly Form _form;

    public FormStateService(Form form)
    {
        _form = form;
        // 初始化状态映射,枚举与状态类一一对应
        _stateMap = new Dictionary<State, FormState>
        {
            { State.Draft, new DraftState() },
            { State.WaitForApprovalManager, new WaitForApprovalManagerState() },
            { State.WaitForApprovalTech, new WaitForApprovalTechState() },
            { State.WaitForApprovalFinance, new WaitForApprovalFinanceState() },
            { State.Afgekeurd, new DeniedState() },
            { State.Afgerond, new ApprovedState() }
        };
        // 根据表单当前状态初始化状态对象,支持从数据库加载的已有表单
        SetCurrentState((State)_form.State);
    }

    private void SetCurrentState(State state)
    {
        _currentState = _stateMap[state];
        _currentState.SetContext(_form);
    }

    // 暴露具体的动作方法,对应用户实际操作
    public void SubmitForm()
    {
        var newState = _currentState.OnSubmit();
        UpdateFormState(newState);
    }

    public void ManagerApprove()
    {
        var newState = _currentState.OnManagerApproval();
        UpdateFormState(newState);
    }

    public void TechApprove()
    {
        var newState = _currentState.OnTechApproval();
        UpdateFormState(newState);
    }

    public void FinanceApprove()
    {
        var newState = _currentState.OnFinanceApproval();
        UpdateFormState(newState);
    }

    public void DenyForm()
    {
        var newState = _currentState.OnDeny();
        UpdateFormState(newState);
    }

    private void UpdateFormState(State? newState)
    {
        if (newState.HasValue)
        {
            _form.State = (int)newState.Value;
            SetCurrentState(newState.Value);
        }
    }

    public State GetCurrentState()
    {
        return (State)_form.State;
    }
}

2. 重新定义抽象状态类(FormState)

public abstract class FormState
{
    protected Form _form;

    public void SetContext(Form form)
    {
        _form = form;
    }

    // 定义各个动作的抽象方法,状态类按需实现(不需要的动作可抛出异常或返回null)
    public abstract State? OnSubmit();
    public abstract State? OnManagerApproval();
    public abstract State? OnTechApproval();
    public abstract State? OnFinanceApproval();
    public abstract State? OnDeny();
}

3. 具体状态类示例(DraftState)

public class DraftState : FormState
{
    public override State? OnSubmit()
    {
        // 集中处理提交时的业务规则
        if (_form.TotalPay < 500)
        {
            return State.WaitForApprovalFinance;
        }
        else if (_form.TotalPay >= 500 && _form.IsTechForm)
        {
            // 技术类且金额>=500,先进入经理审批
            return State.WaitForApprovalManager;
        }
        else if (_form.TotalPay >= 500)
        {
            return State.WaitForApprovalManager;
        }
        return null;
    }

    // 草稿状态下不允许审批操作,抛出异常明确禁止
    public override State? OnManagerApproval() => throw new InvalidOperationException("草稿表单无法进行经理审批");
    public override State? OnTechApproval() => throw new InvalidOperationException("草稿表单无法进行技术审批");
    public override State? OnFinanceApproval() => throw new InvalidOperationException("草稿表单无法进行财务审批");
    public override State? OnDeny() => throw new InvalidOperationException("草稿表单无法拒绝");
}

4. 具体状态类示例(WaitForApprovalManagerState)

public class WaitForApprovalManagerState : FormState
{
    public override State? OnSubmit() => throw new InvalidOperationException("已提交的表单无法重复提交");

    public override State? OnManagerApproval()
    {
        // 经理审批通过后,根据规则跳转
        if (_form.IsTechForm)
        {
            // 技术类表单转到技术审批
            return State.WaitForApprovalTech;
        }
        else
        {
            // 非技术类转到财务审批
            return State.WaitForApprovalFinance;
        }
    }

    public override State? OnTechApproval() => throw new InvalidOperationException("未完成经理审批,无法进行技术审批");
    public override State? OnFinanceApproval() => throw new InvalidOperationException("未完成经理审批,无法进行财务审批");

    public override State? OnDeny()
    {
        return State.Afgekeurd;
    }
}

5. 技术审批状态类(WaitForApprovalTechState)

public class WaitForApprovalTechState : FormState
{
    public override State? OnSubmit() => throw new InvalidOperationException("已提交的表单无法重复提交");
    public override State? OnManagerApproval() => throw new InvalidOperationException("已完成经理审批,无需重复操作");

    public override State? OnTechApproval()
    {
        // 技术审批通过后转到财务审批
        return State.WaitForApprovalFinance;
    }

    public override State? OnFinanceApproval() => throw new InvalidOperationException("未完成技术审批,无法进行财务审批");

    public override State? OnDeny()
    {
        return State.Afgekeurd;
    }
}

6. 财务审批完成状态类(WaitForApprovalFinanceState)

public class WaitForApprovalFinanceState : FormState
{
    public override State? OnSubmit() => throw new InvalidOperationException("已提交的表单无法重复提交");
    public override State? OnManagerApproval() => throw new InvalidOperationException("已完成经理审批,无需重复操作");
    public override State? OnTechApproval() => throw new InvalidOperationException("已完成技术审批,无需重复操作");

    public override State? OnFinanceApproval()
    {
        // 财务审批通过,表单完成
        return State.Afgerond;
    }

    public override State? OnDeny()
    {
        return State.Afgekeurd;
    }
}

改进后的优势

  • 职责清晰:每个状态只处理自己能响应的动作,业务规则集中在对应的触发点
  • 低耦合:新增状态时只需添加对应状态类和映射,无需修改其他状态类
  • 可维护性:修改业务规则时,仅需找到对应动作方法修改,不会影响其他状态
  • 可读性:从代码中能直观看到每个状态下允许的操作,以及操作后的状态转换逻辑

内容的提问来源于stack exchange,提问作者worst_developer69

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 20:24:53