DesignPattern Tutorials

Composite Design Pattern

Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.

Frequency of use:
Medium high




UML class diagram






Participants


    The classes and 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.



Structural 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.

  1. using System;

  2. using System.Collections.Generic;

  3.  

  4. namespace DoFactory.GangOfFour.Composite.Structural

  5. {

  6.   /// <summary>

  7.   /// MainApp startup class for Structural

  8.   /// Composite Design Pattern.

  9.   /// </summary>

  10.   class MainApp

  11.   {

  12.     /// <summary>

  13.     /// Entry point into console application.

  14.     /// </summary>

  15.     static void Main()

  16.     {

  17.       // Create a tree structure

  18.       Composite root = new Composite("root");

  19.       root.Add(new Leaf("Leaf A"));

  20.       root.Add(new Leaf("Leaf B"));

  21.  

  22.       Composite comp = new Composite("Composite X");

  23.       comp.Add(new Leaf("Leaf XA"));

  24.       comp.Add(new Leaf("Leaf XB"));

  25.  

  26.       root.Add(comp);

  27.       root.Add(new Leaf("Leaf C"));

  28.  

  29.       // Add and remove a leaf

  30.       Leaf leaf = new Leaf("Leaf D");

  31.       root.Add(leaf);

  32.       root.Remove(leaf);

  33.  

  34.       // Recursively display tree

  35.       root.Display(1);

  36.  

  37.       // Wait for user

  38.       Console.ReadKey();

  39.     }

  40.   }

  41.  

  42.   /// <summary>

  43.   /// The 'Component' abstract class

  44.   /// </summary>

  45.   abstract class Component

  46.   {

  47.     protected string name;

  48.  

  49.     // Constructor

  50.     public Component(string name)

  51.     {

  52.       this.name = name;

  53.     }

  54.  

  55.     public abstract void Add(Component c);

  56.     public abstract void Remove(Component c);

  57.     public abstract void Display(int depth);

  58.   }

  59.  

  60.   /// <summary>

  61.   /// The 'Composite' class

  62.   /// </summary>

  63.   class Composite : Component

  64.   {

  65.     private List<Component> _children = new List<Component>();

  66.  

  67.     // Constructor

  68.     public Composite(string name)

  69.       : base(name)

  70.     {

  71.     }

  72.  

  73.     public override void Add(Component component)

  74.     {

  75.       _children.Add(component);

  76.     }

  77.  

  78.     public override void Remove(Component component)

  79.     {

  80.       _children.Remove(component);

  81.     }

  82.  

  83.     public override void Display(int depth)

  84.     {

  85.       Console.WriteLine(new String('-', depth) + name);

  86.  

  87.       // Recursively display child nodes

  88.       foreach (Component component in _children)

  89.       {

  90.         component.Display(depth + 2);

  91.       }

  92.     }

  93.   }

  94.  

  95.   /// <summary>

  96.   /// The 'Leaf' class

  97.   /// </summary>

  98.   class Leaf : Component

  99.   {

  100.     // Constructor

  101.     public Leaf(string name)

  102.       : base(name)

  103.     {

  104.     }

  105.  

  106.     public override void Add(Component c)

  107.     {

  108.       Console.WriteLine("Cannot add to a leaf");

  109.     }

  110.  

  111.     public override void Remove(Component c)

  112.     {

  113.       Console.WriteLine("Cannot remove from a leaf");

  114.     }

  115.  

  116.     public override void Display(int depth)

  117.     {

  118.       Console.WriteLine(new String('-', depth) + name);

  119.     }

  120.   }

  121. }

  122.  
  123.  

Output
-root
---Leaf A
---Leaf B
---Composite X
-----Leaf XA
-----Leaf XB
---Leaf C


Real-world code in 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).

  1. using System;

  2. using System.Collections.Generic;

  3.  

  4. namespace DoFactory.GangOfFour.Composite.RealWorld

  5. {

  6.   /// <summary>

  7.   /// MainApp startup class for Real-World

  8.   /// Composite Design Pattern.

  9.   /// </summary>

  10.   class MainApp

  11.   {

  12.     /// <summary>

  13.     /// Entry point into console application.

  14.     /// </summary>

  15.     static void Main()

  16.     {

  17.       // Create a tree structure

  18.       CompositeElement root =

  19.         new CompositeElement("Picture");

  20.       root.Add(new PrimitiveElement("Red Line"));

  21.       root.Add(new PrimitiveElement("Blue Circle"));

  22.       root.Add(new PrimitiveElement("Green Box"));

  23.  

  24.       // Create a branch

  25.       CompositeElement comp =

  26.         new CompositeElement("Two Circles");

  27.       comp.Add(new PrimitiveElement("Black Circle"));

  28.       comp.Add(new PrimitiveElement("White Circle"));

  29.       root.Add(comp);

  30.  

  31.       // Add and remove a PrimitiveElement

  32.       PrimitiveElement pe =

  33.         new PrimitiveElement("Yellow Line");

  34.       root.Add(pe);

  35.       root.Remove(pe);

  36.  

  37.       // Recursively display nodes

  38.       root.Display(1);

  39.  

  40.       // Wait for user

  41.       Console.ReadKey();

  42.     }

  43.   }

  44.  

  45.   /// <summary>

  46.   /// The 'Component' Treenode

  47.   /// </summary>

  48.   abstract class DrawingElement

  49.   {

  50.     protected string _name;

  51.  

  52.     // Constructor

  53.     public DrawingElement(string name)

  54.     {

  55.       this._name = name;

  56.     }

  57.  

  58.     public abstract void Add(DrawingElement d);

  59.     public abstract void Remove(DrawingElement d);

  60.     public abstract void Display(int indent);

  61.   }

  62.  

  63.   /// <summary>

  64.   /// The 'Leaf' class

  65.   /// </summary>

  66.   class PrimitiveElement : DrawingElement

  67.   {

  68.     // Constructor

  69.     public PrimitiveElement(string name)

  70.       : base(name)

  71.     {

  72.     }

  73.  

  74.     public override void Add(DrawingElement c)

  75.     {

  76.       Console.WriteLine(

  77.         "Cannot add to a PrimitiveElement");

  78.     }

  79.  

  80.     public override void Remove(DrawingElement c)

  81.     {

  82.       Console.WriteLine(

  83.         "Cannot remove from a PrimitiveElement");

  84.     }

  85.  

  86.     public override void Display(int indent)

  87.     {

  88.       Console.WriteLine(

  89.         new String('-', indent) + " " + _name);

  90.     }

  91.   }

  92.  

  93.   /// <summary>

  94.   /// The 'Composite' class

  95.   /// </summary>

  96.   class CompositeElement : DrawingElement

  97.   {

  98.     private List<DrawingElement> elements =

  99.       new List<DrawingElement>();

  100.  

  101.     // Constructor

  102.     public CompositeElement(string name)

  103.       : base(name)

  104.     {

  105.     }

  106.  

  107.     public override void Add(DrawingElement d)

  108.     {

  109.       elements.Add(d);

  110.     }

  111.  

  112.     public override void Remove(DrawingElement d)

  113.     {

  114.       elements.Remove(d);

  115.     }

  116.  

  117.     public override void Display(int indent)

  118.     {

  119.       Console.WriteLine(new String('-', indent) +

  120.         "+ " + _name);

  121.  

  122.       // Display each child element on this node

  123.       foreach (DrawingElement d in elements)

  124.       {

  125.         d.Display(indent + 2);

  126.       }

  127.     }

  128.   }

  129. }

  130.  

Output
-+ Picture
--- Red Line
--- Blue Circle
--- Green Box
---+ Two Circles
----- Black Circle
----- White Circle
;