Composite

Summary:  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.

     

using System;

using System.Collections.Generic;

 

namespace DoFactory.GangOfFour.Composite.Structural

{

  /// <summary>

  /// MainApp startup class for Structural

  /// Composite Design Pattern.

  /// </summary>

  class MainApp

  {

    /// <summary>

    /// Entry point into console application.

    /// </summary>

    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.ReadKey();

    }

  }

 

  /// <summary>

  /// The 'Component' abstract class

  /// </summary>

  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);

  }

 

  /// <summary>

  /// The 'Composite' class

  /// </summary>

  class Composite : Component

  {

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

 

    // 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);

      }

    }

  }

 

  /// <summary>

  /// The 'Leaf' class

  /// </summary>

  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

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

    

using System;

using System.Collections.Generic;

 

namespace DoFactory.GangOfFour.Composite.RealWorld

{

  /// <summary>

  /// MainApp startup class for Real-World

  /// Composite Design Pattern.

  /// </summary>

  class MainApp

  {

    /// <summary>

    /// Entry point into console application.

    /// </summary>

    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"));

 

      // Create a branch

      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.ReadKey();

    }

  }

 

  /// <summary>

  /// The 'Component' Treenode

  /// </summary>

  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);

  }

 

  /// <summary>

  /// The 'Leaf' class

  /// </summary>

  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);

    }

  }

 

  /// <summary>

  /// The 'Composite' class

  /// </summary>

  class CompositeElement : DrawingElement

  {

    private List<DrawingElement> elements =

      new List<DrawingElement>();

 

    // 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 d in elements)

      {

        d.Display(indent + 2);

      }

    }

  }

}

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

.NET Optimized code in C#


The .NET optimized code demonstrates the same real-world situation as above but uses modern, built-in .NET features, such as, generics, reflection, LINQ, lambda functions, and more. You can find an example on our Singleton pattern page.

All other patterns, and so much more, are available in our Dofactory .NET product.


Dofactory .NET includes the Gang of Four and Enterprise patterns, but also many other innovations including our Ultra-Clean™ Architecture, powerful low-code tactics, Rapid Application Development (RAD) techniques, and much more.

Accelerate your application development to where you can write entire solutions in just 33 days!. This unique package will change your outlook on development and your career.  Here's what is included:






Dofactory .NET
.NET Developer Pack




Learn More



  • 69 gang-of-four pattern projects
  • 46 head-first pattern projects
  • Fowler's enterprise patterns
  • Multi-tier patterns
  • Convention over configuration
  • Active Record and CQRS patterns
  • Repository and Unit-of-Work patterns
  • MVC, MVP, & MVVM patterns
  • SparkTM Rapid App Dev (RAD) data access
  • Complete Analytics, Dashboard App
  • Complete Art Shop, Ecommerce App
  • Complete SaaS, Multi-Tenant App
  • Complete CRM, Customer Relationship App
  • 33-Day App Factory™
  • Everything 100% source code




Stay Inspired!
Join other developers and designers who have already signed up for our mailing list.
Terms     Privacy     Licensing       EULA       Sitemap      
© Data & Object Factory, LLC.
Made with    in Austin, Texas