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

如何使用Dart增强枚举实现状态模式(State Pattern)

基于Dart增强枚举的状态模式实现方案

首先直接解决你遇到的两个核心问题:

  • 枚举构造函数必须是const、无法持有AtmMachine实例的问题:不需要把AtmMachine存在枚举的字段里,把上下文实例作为参数传入枚举的行为方法即可,完全符合状态模式的设计要求。
  • 关于switch分支的顾虑:如果使用枚举值单独覆写方法的写法,完全不需要写switch;就算用统一方法加内部switch,所有分支逻辑也都收敛在枚举内部,业务调用方不需要做任何状态判断,没有违背状态模式“消除业务层分支判断”的核心目标。

推荐实现(无switch,纯多态)

这种写法和你原本的多态实现逻辑完全等价,用增强枚举的枚举值单独覆写接口方法,不需要定义四个独立的状态类,代码更紧凑:

void main() {
  final atmMachine = AtmMachine();
  atmMachine.insertCard();
  atmMachine.ejectCard();
  atmMachine.insertCard();
  atmMachine.insertPin(1234);
  atmMachine.requestCash(2000);
  atmMachine.insertCard();
  atmMachine.insertPin(1234);
}

// 用增强枚举代替原本的抽象类+四个实现类
enum AtmState {
  noCard {
    @override
    void insertCard(AtmMachine machine) {
      print('Please enter a pin.');
      machine.setNewAtmState(hasCard);
    }

    @override
    void ejectCard(AtmMachine machine) {
      print('Please enter a card first.');
    }

    @override
    void insertPin(AtmMachine machine, int pin) {
      print('Please enter a card first.');
    }

    @override
    void requestCash(AtmMachine machine, int cashToWithdraw) {
      print('Please enter a card first.');
    }
  },
  hasCard {
    @override
    void insertCard(AtmMachine machine) {
      print('You cannot enter more than one card.');
    }

    @override
    void ejectCard(AtmMachine machine) {
      print('Card ejected');
      machine.correctPinEntered = false;
      machine.setNewAtmState(noCard);
    }

    @override
    void insertPin(AtmMachine machine, int pin) {
      if (pin == 1234) {
        print('Correct pin');
        machine.correctPinEntered = true;
        machine.setNewAtmState(hasPin);
      } else {
        print('Wrong pin');
        machine.correctPinEntered = false;
        print('Card ejected');
        machine.setNewAtmState(noCard);
      }
    }

    @override
    void requestCash(AtmMachine machine, int cashToWithdraw) {
      print('Enter pin first');
    }
  },
  hasPin {
    @override
    void insertCard(AtmMachine machine) {
      print('You cannot enter more than one card.');
    }

    @override
    void ejectCard(AtmMachine machine) {
      print('Card ejected');
      machine.correctPinEntered = false;
      machine.setNewAtmState(noCard);
    }

    @override
    void insertPin(AtmMachine machine, int pin) {
      print('Already entered pin');
    }

    @override
    void requestCash(AtmMachine machine, int cashToWithdraw) {
      if (cashToWithdraw > machine.cashInMachine) {
        print('There is not enough cash in this machine');
        ejectCard(machine);
      } else {
        print('You got $cashToWithdraw dollars');
        machine.setCashInMachine(machine.cashInMachine - cashToWithdraw);
        ejectCard(machine);
        if (machine.cashInMachine <= 0) {
          machine.setNewAtmState(noCash);
        }
      }
    }
  },
  noCash {
    @override
    void insertCard(AtmMachine machine) {
      print('We do not have money');
    }

    @override
    void ejectCard(AtmMachine machine) {
      print('We do not have money');
    }

    @override
    void insertPin(AtmMachine machine, int pin) {
      print('We do not have money');
    }

    @override
    void requestCash(AtmMachine machine, int cashToWithdraw) {
      print('We do not have money');
    }
  };

  // 定义状态的公共行为接口
  void insertCard(AtmMachine machine);
  void ejectCard(AtmMachine machine);
  void insertPin(AtmMachine machine, int pin);
  void requestCash(AtmMachine machine, int cashToWithdraw);
}

// 上下文类,代码比原本简化很多
class AtmMachine {
  AtmMachine() {
    atmState = cashInMachine <= 0 ? AtmState.noCash : AtmState.noCard;
  }

  AtmState atmState = AtmState.noCard;
  int cashInMachine = 2000;
  bool correctPinEntered = false;

  void setNewAtmState(AtmState value) {
    atmState = value;
  }

  void setCashInMachine(int value) {
    cashInMachine = value;
  }

  // 委托给当前枚举状态的方法,传入自身作为上下文
  void insertCard() => atmState.insertCard(this);
  void ejectCard() => atmState.ejectCard(this);
  void insertPin(int pin) => atmState.insertPin(this, pin);
  void requestCash(int amount) => atmState.requestCash(this, amount);
}

实现说明

  • 所有状态都是编译期常量,不需要在AtmMachine初始化时手动创建四个状态实例,省去了大量late变量声明和初始化代码。
  • 状态逻辑完全封装在AtmState枚举内部,上下文类和外部调用方不需要感知具体状态类型,直接调用方法即可,完全符合状态模式的设计原则。
  • 相比单独定义四个状态类,所有状态逻辑集中在同一个枚举中,维护时不需要在多个文件间跳转。

如果状态数量多、存在大量公共逻辑,也可以选择在枚举的统一方法中用switch处理不同状态的逻辑,把公共代码抽出来复用,这种写法下switch是枚举内部的实现细节,不会泄露到业务层,同样是合理的实现方式。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 06:30:53