如何使用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
相关产品推荐
相关产品推荐

