Per the Gang of Four book, the command pattern parameterizes objects by an object to perform. Also from the same book, commands are an object-oriented replacement for callback functions. I spent some time getting the object-oriented version working last night in Dart, tonight I replace it with the callback version.
In the client code, I am still using the same invoker and receiver from last night:
// Invoker
var s = new Switch();
// Receiver
var lamp = new Light();
Previously, I had stored the on/off actions on the lamp as commands: var switchUp = new OnCommand(lamp),
switchDown = new OffCommand(lamp);
Those commands bind the receiver and an action as they are supposed to in this pattern:class OnCommand implements Command { Light light; OnCommand(this.light); void execute() { light.turn('ON'); } }To replace this (and the
OffCommand
) with callbacks, I need to similarly bind receiver and action. That is a fairly easy task: // Commands
var switchUp = (){ lamp.turn('ON'); },
switchDown = (){ lamp.turn('OFF'); };
At the risk of saying something nice about callbacks and the spaghetti that they so often beget, I must admit that the callbacks are far more concise than the equivalent command objects. This is Dart, so the commands were not that much trouble. Still both callback-commands are one-liners. That is a definite improvement. I am not quite done converting to callbacks. The command objects supported an
execute()
method. Dart functions all support a call()
method to invoke the function. So the invoker code for executed the store command needs to invoke call()
now:class Switch { List<Function> _history = []; void storeAndExecute(Function c) { c.call(); _history.add(c); } // ... }Similarly, the simple undo method also needs to use
call()
: void undo() {
_history.
reversed.
forEach((c) { c.call(); });
}
With that, the code that invokes the invoker should work: switch (command) {
case 'on':
s.storeAndExecute(switchUp);
break;
case 'off':
s.storeAndExecute(switchDown);
break;
// ...
}
And work it does. I can turn the lamp on and off and reverse the order as desired:$ ./bin/press_switch.dart on off on on Light ON Light OFF Light ON Light ON -- Light ON Light ON Light OFF Light ONThat is exactly how the command object behaved last night.
Is one way better than the other? The callback version tonight is a definite step up in clarity and lesser amount of code. I imagine that command objects still have their place. I will see if I can find them… starting tomorrow.
Play with this code on DartPad: https://dartpad.dartlang.org/719748d72bafeeefaab1.
Day #26
No comments:
Post a Comment