The Composite pattern is intended to allow you to compose tree structures to represent whole-part hierarchies so that clients can treat individual objects and compositions of objects uniformly.
When I hear "composite pattern", immediately XML pops up in my mind. A composite is an element and a leaf is an attribute.
<composite>
<composite leaf="value">
Important Text
</composite>
</composite>
The client creates the root of the tree and adds composites and leafs. Next an operation can be performed on the complete tree by calling the method on the root. Thereafter the operation is ‘automagically’ called recursively.
class Client
{
static void Main(string[] args)
{
Composite root = new Composite("composite1");
// add a leaf root.Add(new Leaf("leaf1"));
//example of removing a leaf Leaf leaf = new Leaf("leaf2");
root.Add(leaf);
root.Remove(leaf);
root.Add(new Leaf("leaf3"));
//adding another composite Composite comp = new Composite("composite2");
comp.Add(new Leaf("leaf1"));
root.Add(comp);
// recursively operation int depth = 1;
root.Operation(depth);
Console.ReadKey();
}
}
The key of this pattern is the abstract class Component, which is the parent of the composite object and leaf. It defines a property and an operation. It also has methods for adding and removing objects from the tree. These methods are not necessary, but – indeed – very convenient.
abstract class Component
{
protected string name;
public Component(string name)
{
this.name = name;
}
public abstract void Add(Component component);
public abstract void Remove(Component component);
//this is the key operation
public abstract void Operation(int depth);
}
The composite is the concrete class which implements all methods of the abstract parent class, thus can contain another composite or leaf.
class Composite : Component
{
private List m_Children = new List();
// Constructor
public Composite(string name) : base(name) { }
public override void Add(Component component)
{
m_Children.Add(component);
}
public override void Remove(Component component)
{
m_Children.Remove(component);
}
public override void Operation(int depth)
{
if (depth > 1) Console.WriteLine(">");
Console.Write(new String(' ', depth) + string.Format("< {0}", name));
// Recursively display child nodes
foreach (Component component in m_Children)
{
component.Operation(depth + 2);
}
Console.WriteLine(">");
Console.Write(new String(' ', depth) + string.Format("< {0}", name));
if (depth == 1) Console.WriteLine(">");
}
}
The leaf, on the other hand, is a crippled implementation of the abstract parent class. It cannot contain other parts, it is an endpoint.
In this example, a xml-structure is created and the method Operation is use to display itself. Therefore, Display() would be a better name. Maybe we should refactor it.
This post is part of a series on the foundational design patterns in C#. In this series we explore the ancient design patterns and their use in real-world programming situations of today. In these series of posts we explore each pattern by looking at a minimalistic example to reveal its structure and then look at more concrete and useful real-world C# code that implements the pattern.