Daily Patterns #11
-
Upload
oleg-godovykh -
Category
Documents
-
view
217 -
download
0
Transcript of Daily Patterns #11
-
7/31/2019 Daily Patterns #11
1/3
Child managementmethods [e.g. addChild(),
removeChild()] should normally bedefined in the Composite class.
Unfortunately, the desire to treat
Primitives and Composites uniformlyrequires that these methods be moved tothe abstract Component class. See the
Opinions section below for adiscussion of safety versus
transparency issues.
Composite DESIGN PATTERN
INTENT
Compose objects into tree structures torepresent whole-part hierarchies.
Composite lets clients treat individualobjects and compositions of objects
uniformly.
Recursive compositionDirectories contain entries, each of which
could be a directory.
1-to-many has a up the is a hierarchy
Problem
Application needs to manipulate ahierarchical collection of primitive and
composite objects. Processing of aprimitive object is handled one way, andprocessing of a composite object is
handled differently. Having to query thetype of each object before attempting to
process it is not desirable.
Define an abstract baseclass (Component) that specifiesthe behavior that needs to be
exercised uniformly across all primitive
and composite objects. Subclass thePrimitive and Composite classes off of theComponent class. Each Composite object
couples itself only to the abstracttype Component as it manages its
children.
Use this pattern whenever you havecomposites that contain components,each of which could be a composite.
-
7/31/2019 Daily Patterns #11
2/3
Composites that containComponents, each of which couldbe a Composite.
Menusthat contain menu
items, each of which couldbe a menu.
Row-column GUI layout managersthat contain widgets, each of whichcould be a row-column GUI layout
manager.
Directories that contain files, each ofwhich could be a directory.
Containers that containElements, each of which
could be aContainer.
The Composite composesobjects into tree structuresand lets clients treatindividual objects andcompositions uniformly.Although the example isabstract, arithmeticexpressions are Composites.An arithmetic expressionconsists of an operand, anoperator (+ - * /), and anotheroperand. The operand can be anumber, or another arithmeticexpresssion. Thus, 2 + 3 and (2+ 3) + (4 * 6) are both validexpressions.
1. Ensure thatyour problemis aboutrepresenting
whole-parthierarchicalrelationships.
2. Consider the heuristic, Containers thatcontain containees, each of which couldbe a container. For example, Assembliesthat contain components, each of which
could be an assembly. Divide your domainconcepts into container classes, andcontainee classes.
3. Create a lowestcommon denominatorinterface that makesyour containers and
containeesinterchangeable. Itshould specify thebehavior that needsto be exerciseduniformly across all
containee andcontainer objects.
4. All container andcontainee classes declarean is a relationship tothe interface.
5. All container classesdeclare a one-to-manyhas a relationship to theinterface.
6. Container classesleverage polymorphism to
delegate to theircontainee objects.
7. Child management methods [e.g. addChild(),removeChild()] should normally be defined in the
Composite class. Unfortunately, the desire to treatLeaf and Composite objects uniformly may requirethat these methods be promoted to the abstract
Component class. See the Gang of Four for adiscussion of these safety versus transparencytrade-offs.
-
7/31/2019 Daily Patterns #11
3/3
Smalltalk implementationsof the Composite pattern usually do
not have the interface for managing thecomponents in the Component interface,
but in the Composite interface. C++
implementations tend to put it in theComponent interface. This is an extremelyinteresting fact, and one that I often
ponder. I can offer theories to explainit, but nobody knows for sure why it is
true.
The whole point of the Compositepattern is that the Composite can be
treated atomically, just like a leaf. If youwant to provide an Iterator protocol, fine,but I think that is outside the pattern itself.
At the heart of this pattern is the abilityfor a client to perform operations on an
object without needing to know thatthere are many objects inside.
Composite and Decorator havesimilar structure diagrams,reflecting the fact that bothrely on recursive composition toorganize an open-ended numberof objects.
Composite can be traversed withIterator. Visitor can apply anoperation over a Composite.Composite could use Chain ofResponsibility to letcomponents access globalproperties through their parent.It could also use Decorator tooverride these properties onparts of the composition. Itcould use Observer to tie oneobject structure to another and
State to let a component changeits behavior as its state changes.
Composite can let you compose aMediator out of smaller pieces
through recursive composition.
Decorator is designed to let youadd responsibilities to objectswithout subclassing. Compositesfocus is not on embellishmentbut on representation. These
intents are distinct butcomplementary. Consequently,Composite and Decorator areoften used in concert.
Flyweight is often combined withComposite to implement sharedleaf nodes.
Being able totreat a heterogeneous collection
of objects atomically (ortransparently) requires that the childmanagement interface be defined at the
root of the Composite class hierarchy (theabstract Component class). However, thischoice costs you safety, because clients
may try to do meaningless things like add
and remove objects from leaf objects. Onthe other hand, if you design for safety,the child management interface is
declared in the Composite class, and youlose transparency because leaves and
Composites now have differentinterfaces.
My Component classesdo not know that
Composites exist. Theyprovide no help for
navigating Composites,nor any help for
altering the contents ofa Composite. This is
because I would like thebase class (and all its
derivatives) to bereusable in contextsthat do not require
Composites. When given abase class pointer, if I
absolutely need to know
whether or not it is aComposite, I will usedynamic_cast to figure
this out. In those caseswhere dynamic_cast istoo expensive, I will
use a Visitor.
Common complaint:if I push the
Composite interfacedown into the
Composite class, how
am I going toenumerate (i.e.traverse) a complex
structure? My answeris that when I have
behaviors which applyto hierarchies like the
one presented in theComposite pattern, Itypically use Visitor,so enumeration isnt aproblem - the Visitorknows in each case,exactly what kind ofobject its dealing
with. The Visitordoesnt need every
object to provide anenumerationinterface.
Composite doesnt forceyou to treat all Components
as Composites. It merelytells you to put all
operations that you want totreat uniformly in the
Component class. If add,remove, and similar
operations cannot, or mustnot, be treated uniformly,
then do not put them in theComponent base class.
Remember, by the way, thateach patterns structure
diagram doesnt define thepattern; it merely depictswhat in our experience is a
common realization thereof.
Just because Compositesstructure diagram showschild management operationsin the Component base class
doesnt mean allimplementations of the
pattern must do the same.