We've used the Composite pattern within GenomeTopographer
Experiment hierarchy. Experiments have inputs, conditions and
outputs. They also know how to compute themselves. An atomic
experiment is one step in an experimental protocol. The composite
experiments hold multiple atomic experiments, which may execute in sequence
or in parallel depending on how they are linked together. We're
thinking about iterative and conditional links within the composite,
The Composite pattern worked well for this application. Our biggest
challenge has been to remember to not assume that we always have
a composite --- that is, to maintain the common interface.
itself pretty much just represents a
data flow graph of experiments. We associate an Experiment
Prototype with a composite to provide specialized behavior. --MoiraMallison
C3 has a big use of CompositePattern
in its Bin and BinSupply?
objects. It's a nice compact way to do the single/group thing. However, IMO it is rather deep in the bag of tricks and can be tricky to implement. Use when really needed, with caution. --RonJeffries
Composite as a nickname for the idea saved us in several really heated discussions. Someone just said, "that's a composite", and the rest said, "oh. yeah." and that was that.
OTOH, Composite caused quite some trouble with the following design problem: company has legal and sales territories. the top-level legal territories are the same as the top-level sales territories, but after that, they go their own ways, but the trees are always nicely triangular in shape. Certain properties and behaviors attach to the top levels, the middle levels, and the leaf levels in each. The composite pattern does not cope with this top, middle, bottom stuff. OMT (and UML?) couldn't handle the polymorphism. So we used the general idea of Composite, but not the thing written in the book. Each person who joined the project said, "That's wrong. That's not what's in the book." And long, tedious arguments would follow for days until they got that what is in the book does not always work. ugh.
I saw an article in C++ Journal describing CascadingCompositePattern?
The idea is that the leaves of your composite tree can also be instances of the composite pattern.
In other words, you apply the pattern recursively.
To make this concrete, here's how to do the territories:
| | | |
LegalTerritoryComponent SalesTerritoryComponent CompanyComposite
^ | ^ |
| | | |
+------+---+ | +----+-----+ |
| | | | | |
LegalLeaf LegalComposite SalesLeaf SalesComposite
This ensures that the top nodes are CompanyComposite?
, the shared Legal and Sales territories, and that once you get to a Legal or Sales territory, everything under it will be of the same type. I've assumed that there are no CompanyLeafs?
, but adding one is trivial.
As for the inexperienced developers, I wouldn't say that DesignPatterns
is "wrong;" it's only inapplicable to this situation.
And anyway, you're supposed to
modify the design patterns to fit your situation during implementation.
They're patterns, not a code library. -- JeffGrigg
Jeff, I'm not sure I get this. The problem is that while your component and composites share type, and your components are all a kind of
component, you composites are not a kind of
composite. This makes it hard to create a Generic Visitor that simply visits Component
. Of course, the book doesn't handle this either
. That is one of the problems with the composite pattern. It cannot be provide in Java or Smalltalk as an extensible ADT. Each time you use it you must recreate the class hierarchy (except for the component). Any thoughts on this? -- RobertDiFalco
Use the Java interface mechanism. Each base class implements Composite. However, this may violate OnceAndOnlyOnce in some situations as each base class realizes its own copy of the shared composite interface.
I once commented to KentBeck
that I didn't like the "official" DesignPatterns
way of doing composite. He replied, as only he can, "Well, you're much smarter than I am. You can do it that way if you want to ..." --RonJeffries
Okay, Ron, don't leave us guessing. How do you like doing it? More like just another Collection Type (i.e. Abstract Data Type) something like a Tree or Graph? Or using another method alltogether? -- RobertDiFalco
I tend to favor using C++ pure virtual functions in the base classes, as it enables compile-time enforcement of the requirement that child classes implement certain methods.
This deviates from the "official" DesignPatterns
description, which recommends 'implementing (appropriate) default behavior' in the "Component" base class.
I usually add another abstract base class between Component and the Leaf classes, to hold state and behavior that is common to all Leaf classes but different from the Composite class.
I consider these minor implementation variations, rather than heretical deviations from the faith.
Others, I'm sure ;->, would be more than glad to argue.
You should take a look at the Composite and Visitor variations I used in CppUtxOverview
. These allow you to get rid of the virtual functions altogether by trusting the dynamic dispatching done by the Visitor. All the base class (i.e. Component) really needs is the visitor acceptor. -- RobertDiFalco
Moving my controversy to CompositeConsideredHarmful
. We'll see what happens. --RichardHenderson