Composite Design Pattern

participants
The classes and/or objects participating in this pattern are:
- Component (DrawingElement)
- declares the 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.
- Leaf (PrimitiveElement)
- represents leaf objects in the composition. A leaf has no children.
- defines behavior for primitive objects in the composition.
- Composite (CompositeElement)
- defines behavior for components having children.
- stores child components.
- implements child-related operations in the Component interface.
- Client (CompositeApp)
- manipulates objects in the composition through the Component interface.
sample code in C#
This structural code demonstrates the Composite pattern which allows the creation of a tree structure in which individual nodes are accessed uniformly whether they are leaf nodes or branch (composite) nodes.
Hide code
// Composite pattern -- Structural example
|
using System; using System.Collections; namespace DoFactory.GangOfFour.Composite.Structural { // MainApp test application class MainApp { static void Main() { // Create a tree structure Composite root = new Composite("root"); root.Add( new Leaf("Leaf A")); root.Add( new Leaf("Leaf B")); Composite comp = new Composite("Composite X"); comp.Add( new Leaf("Leaf XA")); comp.Add( new Leaf("Leaf XB")); root.Add(comp); root.Add( new Leaf("Leaf C")); // Add and remove a leaf Leaf leaf = new Leaf("Leaf D"); root.Add(leaf); root.Remove(leaf); // Recursively display tree root.Display(1); // Wait for user Console.Read(); } } // "Component" abstract class Component { protected string name; // Constructor public Component( string name) { this.name = name; } public abstract void Add(Component c); public abstract void Remove(Component c); public abstract void Display( int depth); } // "Composite" class Composite : Component { private ArrayList children = new ArrayList(); // Constructor public Composite( string name) : base(name) { } public override void Add(Component component) { children.Add(component); } public override void Remove(Component component) { children.Remove(component); } public override void Display( int depth) { Console.WriteLine( new String('-', depth) + name); // Recursively display child nodes foreach (Component component in children) { component.Display(depth + 2); } } } // "Leaf" class Leaf : Component { // Constructor public Leaf( string name) : base(name) { } public override void Add(Component c) { Console.WriteLine("Cannot add to a leaf"); } public override void Remove(Component c) { Console.WriteLine("Cannot remove from a leaf"); } public override void Display( int depth) { Console.WriteLine( new String('-', depth) + name); } } } |
Output
-root
---Leaf A ---Leaf B ---Composite X -----Leaf XA -----Leaf XB ---Leaf C |
This real-world code demonstrates the Composite pattern used in building a graphical tree structure made up of primitive nodes (lines, circles, etc) and composite nodes (groups of drawing elements that make up more complex elements).
Hide code
// Composite pattern -- Real World example
|
using System; using System.Collections; namespace DoFactory.GangOfFour.Composite.RealWorld { // Mainapp test application class MainApp { static void Main() { // Create a tree structure CompositeElement root = new CompositeElement("Picture"); root.Add( new PrimitiveElement("Red Line")); root.Add( new PrimitiveElement("Blue Circle")); root.Add( new PrimitiveElement("Green Box")); CompositeElement comp = new CompositeElement("Two Circles"); comp.Add( new PrimitiveElement("Black Circle")); comp.Add( new PrimitiveElement("White Circle")); root.Add(comp); // Add and remove a PrimitiveElement PrimitiveElement pe = new PrimitiveElement("Yellow Line"); root.Add(pe); root.Remove(pe); // Recursively display nodes root.Display(1); // Wait for user Console.Read(); } } // "Component" Treenode abstract class DrawingElement { protected string name; // Constructor public DrawingElement( string name) { this.name = name; } public abstract void Add(DrawingElement d); public abstract void Remove(DrawingElement d); public abstract void Display( int indent); } // "Leaf" class PrimitiveElement : DrawingElement { // Constructor public PrimitiveElement( string name) : base(name) { } public override void Add(DrawingElement c) { Console.WriteLine( "Cannot add to a PrimitiveElement"); } public override void Remove(DrawingElement c) { Console.WriteLine( "Cannot remove from a PrimitiveElement"); } public override void Display( int indent) { Console.WriteLine( new String('-', indent) + " " + name); } } // "Composite" class CompositeElement : DrawingElement { private ArrayList elements = new ArrayList(); // Constructor public CompositeElement( string name) : base(name) { } public override void Add(DrawingElement d) { elements.Add(d); } public override void Remove(DrawingElement d) { elements.Remove(d); } public override void Display( int indent) { Console.WriteLine( new String('-', indent) + "+ " + name); // Display each child element on this node foreach (DrawingElement c in elements) { c.Display(indent + 2); } } } } |
Output
-+ Picture
--- Red Line --- Blue Circle --- Green Box ---+ Two Circles ----- Black Circle ----- White Circle |