I was recently looking at a large system that I suspect was developed using
the "command" pattern. E.g. there are objects which coordinate and control
all the activities for certain transaction-like tasks.
My question is: How much logic should be put in the command objects? That
is, should messages sent out by the command objects be fine-grained messages
that micro-manage tasks, or should the command objects send out only a
few coarse-grained message that divides the task up into large chunks
that are natural for the domain? Perhaps only a single message that directs
the appropriate domain object to do all the processing?
Their existance in the first place does not sit well with my notions of OOD,
so I am tyring to see how to derive the benefits of the pattern without
creating a non-OO design in which functionality and data are
seperated instead of combined into objects.
I am especially interested in the use of the pattern when supporting Undo. My
intuition is that the command objects should only be intelligent enough to
divide the task up into subtasks that the other objects in the system can undo
themselves without relying on information that was gathered during the initial
processing (i.e. which screen was open at the time, what was highlighted in a
text window, what was stored in a file or buffer, etc.).
thanks for any and all light people can shed on this issue.
d.
--
Damon Feldman
feld...@erols.com
> I was recently looking at a large system that I suspect was developed using
> the "command" pattern. E.g. there are objects which coordinate and control
> all the activities for certain transaction-like tasks.
>
> My question is: How much logic should be put in the command objects? That
> is, should messages sent out by the command objects be fine-grained messages
> that micro-manage tasks, or should the command objects send out only a
> few coarse-grained message that divides the task up into large chunks
> that are natural for the domain? Perhaps only a single message that directs
> the appropriate domain object to do all the processing?
Use the command pattern when you have a task to perform that coordinates the
activities of one or more domain objects, but is not itself a part of the
domain objects.
For example, you might use a command pattern to draw a rectangle. The command
pattern would know how to interpret the mouse clicks and drags and build the
rectangle object. This separates the rectangle object from the concept
of a mouse.
Or, you could use a command pattern to add a record to an employee database.
The command pattern could make sure that the input to the record was consistent
and that all referential integrity was intact. This frees the employee record
from knowing how they are added, or what needs to be done to ensure that
they are built consistently.
Thus, in every case we use the command pattern to decouple knowledge from
the domain object that the domain object should not have to know.
>
> Their existance in the first place does not sit well with my notions of OOD,
> so I am tyring to see how to derive the benefits of the pattern without
> creating a non-OO design in which functionality and data are
> seperated instead of combined into objects.
Not all functionality relevant to a domain object should be a method of
a domain object. For example, consider a modem class. A behavior that
is relevant to a modem is "ConfigureForUnix". However this behavior should
not be a method of Modem since there is no end to them. You will be adding
ConfigureForXXX methods to the modem class for every new operating system
that comes along. Rather, we would like to see the ConfigureForXXX behaviors
placed into command objects decoupled from the Modem class.
--
Robert C. Martin | Design Consulting | Training courses offered:
Object Mentor | rma...@oma.com | Object Oriented Design
14619 N Somerset Cr | Tel: (847) 918-1004 | C++
Green Oaks IL 60048 | Fax: (847) 918-1023 | http://www.oma.com
"One of the great commandments of science is:
'Mistrust arguments from authority.'" -- Carl Sagan
Instead of adding a new method to the modem class you will add a new
class to your system. These new classes will each have a single method
called "config()"??? This is the part of controller classes that drives
me crazy. You consider it better to add a class rather than a method.
I argue that adding a method to a class is increasing complexity less
than adding a new class to an existing system. In fact, in this example
your classes are really methods. Isn't this a proliferation of classes.
I agree with the original poster, controller classes are dangerous things
in this context. (I know this is the same old argument....but hey, it's
the holiday season :-)
Arthur Riel
> Robert C. Martin wrote:
> > [......]
> > Not all functionality relevant to a domain object should be a method of
> > a domain object. For example, consider a modem class. A behavior that
> > is relevant to a modem is "ConfigureForUnix". However this behavior should
> > not be a method of Modem since there is no end to them. You will be adding
> > ConfigureForXXX methods to the modem class for every new operating system
> > that comes along. Rather, we would like to see the ConfigureForXXX
behaviors
> > placed into command objects decoupled from the Modem class.
>
> Instead of adding a new method to the modem class you will add a new
> class to your system. These new classes will each have a single method
> called "config()"??? This is the part of controller classes that drives
> me crazy. You consider it better to add a class rather than a method.
Correct.
Consider that we have 20 applications that reuse the modem class. Some
of these applications run on Windows and some run on Unix and some
run on the Macintosh.
Now I add a new application, and it runs on B. Am I now to add a
ConfigToB method to the modem class and then rebuild all 20 applications
that have nothing to do with B? Or am I to add a new command or visitor
class and use it in the B application without affecting the 20 others?
Seems a simple choice to me.
> Consider that we have 20 applications that reuse the modem class. Some
> of these applications run on Windows and some run on Unix and some
> run on the Macintosh.
>
> Now I add a new application, and it runs on B. Am I now to add a
> ConfigToB method to the modem class and then rebuild all 20 applications
> that have nothing to do with B? Or am I to add a new command or visitor
> class and use it in the B application without affecting the 20 others?
>
> Seems a simple choice to me.
>
Until the public interface of the modem class changes and you need to
figure out which classes in which applications need to be modified.
Good Luck!
Arthur
Wait a minute...Aren't you the one that advocates changing the public
interface?
> Robert C. Martin wrote:
>
> > Consider that we have 20 applications that reuse the modem class. Some
> > of these applications run on Windows and some run on Unix and some
> > run on the Macintosh.
> >
> > Now I add a new application, and it runs on B. Am I now to add a
> > ConfigToB method to the modem class and then rebuild all 20 applications
> > that have nothing to do with B? Or am I to add a new command or visitor
> > class and use it in the B application without affecting the 20 others?
> >
> > Seems a simple choice to me.
> >
>
> Until the public interface of the modem class changes and you need to
> figure out which classes in which applications need to be modified.
> Good Luck!
Good Luck indeed! But I already have this problem. Whether I put all
the ConfigToXXX methods into Modem, or put them into command/visitor
objects is irrelevant. If the interface of Modem changes, all the classes
that #include modem.h (or whatever) will need to be changed.