Upload
katherine-hamilton
View
215
Download
0
Embed Size (px)
Citation preview
Composite Design Pattern
Motivation – Dynamic Structure
aPicture
aPicture aLine aRectangle
aText aLine aRectangle
Motivation – Static Structure
Draw() Add(Graphic) Remove(Graphic) GetChild(int)
Graphic
Draw() Add(Graphic) Remove(Graphic) GetChild(int)
Picture
Draw()
Text
Draw()
Rectange
Draw()
Line
for all g in childreng.Draw()
add g to list of graphics
Applicability
• Use the Composite pattern when:– You need to represent part-whole hierarchies of objects– You want clients to ignore the differences between parts
and wholes (individual objects and compositions of objects)
– The compositions are created dynamically – at run time – so use composite:• when you need to build a complex system from primitive
components and previously defined subsystems.• This is especially important when the construction process will
reuse subsystems defined earlier.
Structure
Operation() Add(Component) Remove(Component) GetChild(int)
Component
Operation() Add(Component) Remove(Component) GetChild(int)
Composite
Operation()
Leaf_C
Operation()
Leaf_B
Operation()
Leaf_A
for all g in childreng.Operation()
add g to list of components
Participants – Plan A
• Component (Graphic)– declares interface for objects in the composition– implements default behavior for the interface common to all
classes, as appropriate– declares an interface for accessing and managing its child
components– (optional) defines an interface for accessing a component’s parent
in the recursive structure, and implements it if that’s appropriate
• Client– manipulates objects in the composition through the Component
interface
Participants – Plan A
• Leaf– Represents leaf objects in the composition. A leaf has no
children.– Defines behavior for primitive objects in the composition.
• Composite (picture)– Defines behavior for components having children.– Stores child components.– Implements child-related operations in the Component
interface.
Structure
Operation()
Component
Operation() Add(Component) Remove(Component) GetChild(int)
Composite
Operation()
Leaf_C
Operation()
Leaf_B
Operation()
Leaf_A
for all g in childreng.Operation()
add g to list ofcomponents
Participants – Plan B
• Component (Graphic)– declares interface for objects in the composition
• Client– manipulates objects in the composition through
the Composite interface
Participants – Plan B
• Leaf– Represents leaf objects in the composition. A leaf has no
children.– Defines behavior for primitive objects in the composition.
• Composite (picture)– Defines behavior for components having children.– declares an interface for accessing and managing its child
components – Stores child components.– Implements child-related operations in the Component
interface.
Collaborators
• Plan A:Clients use the Component class interface to interact with objects in the composite structure.
• Plan B:Clients use the Composite class interface to interact with objects in the composite structure.
– If the recipient is a Leaf then the request is handled directly.
– If the recipient is a composite, then it usually forwards request to its child components.
virtual Operation() virtual Add(node) virtual Remove(node) GetChild(int)
node
Operation() Add(node) Remove(node) GetChild(int)
Tree
for all n in childrenn.Operation()
add n to list of nodes
Tree Structure
Consequences
• The Composite pattern:– Defines class hierarchies consisting of primitives and composites– When a client expects a primitive it can also take a composite.– Makes it easier to add new components.
• Newly defined primitives or composites will work automatically with existing structures and client code.
– Can make your design too general.• Since its easy to add new components it is hard to restrict the
components of a composite.• Composite doesn’t support using the type system to support these
constraints for you, since all components have the same base type.
14
Directory / File Example – Object Structure
/
bin/ user/ tmp/
file1 file2 subdir/ file3
file4 file5
Composite
Composite Composite Composite
CompositeLeaf Leaf Leaf
Leaf Leaf
• Directory = Composite• File = Leaf
15
Directory / File Example – Classes
• One class for Files (Leaf nodes)• One class for Directories (Composite nodes)– Collection of Directories and Files
• How do we make sure that Leaf nodes and Composite nodes can be handled uniformly?– Derive them from the same abstract base class
Leaf Class: File Composite Class: Directory
16
Directory / File Example – Structure
Abstract Base Class: Node
Leaf Class: File Composite Class: Directory
17
Directory / File Example – Operation
Abstract Base Class: Node size() in bytes of entire directory and sub-directories
Leaf Class: File size () of file
Composite Class: Directory size () Sum of file sizes in this directory and its sub-directories
long Directory::size () { long total = 0; Node* child; for (int i = 0; child = getChild(); ++i; { total += child->size(); } return total;}
18
Inventory Example – Problems to Consider
Abstract Base Class: Inventory Item
Leaf Class: Object
Composite Class: Container
Backpack
Cloth Bag Jeweled Dagger
Ruby Ring Wine Bottle
Do you really want all leaf Operations to be defined in Component class?Is Wine Bottle a Composite or does it have an operation for Fill(Liquid)?If Ruby is pried from Dagger, how will this be handled?Would you allow user to put other items in the wine bottle?How do you handle the relative size of items to be placed in a backpack?
19
Consequences
• Solves problem of how to code recursive hierarchical part-whole relationships.
• Client code is simplified.– Client code can treat primitive objects and composite
objects uniformly.– Existing client code does not need changes if a new leaf or
composite class is added (because client code deals with the abstract base class).
• Can make design overly general.– Can’t rely on type system to restrict the components of a
composite. Need to use run-time checks.