When: There is a proliferation of similar methods, and the interface to implement that kind of object is becoming unwieldy.
Symptoms: Too many public methods for other objects to call. An interface that is unworkable and always changing. You feel that a method name must include prose describing the exact action, and this is preventing layering your code.
A command object is a case of using a value object to communicate which action is to be performed, along with any argument data. This is sent to a single method in the class that handles commands of the given type. That object is free to implement command processing with a switch, a variable method dispatch, or a call to a variable subclass. This lets you make changes to which commands are defined only in the definition of the command objects itself and the classes that actually use that command, rather than every class that wants to implement the command processing interface. It also frees up the command implementing the command processing interface to use any number of ideas for dispatching the command, once it has it:
# example of a switch style arrangement:Since Perl offers //AUTOLOAD//, this idea could be emulated. If a package wanted to process an arbitrary and growing collection of commands to the best of its ability, it could catch all undefined method calls using //AUTOLOAD//, and then attempt to dispatch them (this assumes //%commandHandlers// is set up with a list of object references keyed by method name):sub doCommand { my $me = shift; my $cmd = shift; $cmd->isa('BleahCommand') or die; my $instr = $cmd->getInstructionCode(); if($instr eq 'PUT') { # PUT logic here } elsif($instr eq 'GET') { # GET logic here } # etc }
# example of a variable method call arrangement: sub doCommand { my $me = shift; my $cmd = shift; $cmd->isa('BleahCommand') or die; my $instr = $cmd->getInstructionCode(); my $func = "process_" . $instr; return undef unless defined &$func; return $func->($cmd, @_); }
# example of a variable subclass arrangement. # this assumes that %commandHandlers is set up with a list of object references.
sub doCommand { my $me = shift; my $cmd = shift; $cmd->isa('BleahCommand') or die; my $insr = $cmd->getInstructionCode(); my $objectRef = $commandHandlers{$instr}; return $objectRef ? $objectRef->handleCommand($cmd, @_) : undef; }
sub AUTOLOAD { my $me = shift; (my $methodName) = $AUTOLOAD m/.*::(\\w+)$/; return if $methodName eq 'DESTROY'; my $objectRef = $commandHandlers{$methodName}; return $objectRef ? $objectRef->handleCommand($methodName, @_) : undef; }This converts calls to different methods in the current object to calls to a //handleCommand()// method is different objects. This is an example of using Perl to shoehorn a Command Object pattern onto a non Command Object interface.
The article is originally from Perl Design Patterns Book
External Links
See also: Command object, Design patternss, Threaded command object, Scheduler pattern