Daily Patterns #11

download Daily Patterns #11

of 3

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.