PTOM: The Composite Design Pattern
The Composite Design Pattern
This post talks about the Composite Design Pattern and is part of Pablo’s Topic of the Month – November: Design Patterns. A Composite is a tree structure where each node can be represented as a common type so that they can be acted on in a consistent manner, regardless of their concrete implementations. This allows a consumer of the composite to avoid the complexity of having to distinguish the objects individually. I believe that the posts for PTOM are going to centered around a coffee shop, but I’m having a difficult time thinking of a good composite example around that, so let’s say I’m building coffee machines instead.
Lets pretend that I have a model of a coffee machine and all of its parts. Many of the parts are logical and are made up of only child parts. I might have a class that looks something like the following (simplistically implemented for example purposes):
public class CoffeeMachine
{
public FluxCapacitor FluxCapacitor { get; set; }
public PowerCord PowerCord { get; set; }
}
public interface IPart
{
IEnumerable<IPart> GetChildParts();
}
You will notice that the IPart returns child instances of other IParts. This gives us a recursive structure and lets us act on that structure as a composite. By implementing this interface on all of our parts, when can then walk the hierarchy and perform operations without knowing the details of each implementation. We can implement this on our CoffeeMachine and our other parts like the following:
public class CoffeeMachine : IPart
{
public FluxCapacitor FluxCapacitor { get; set; }
public PowerCord PowerCord { get; set; }
public IEnumerable<IPart> GetChildParts()
{
yield return FluxCapacitor;
yield return PowerCord;
}
}
public class FluxCapacitor : IPart
{
public Switch Switch { get; set; }
public PowerBooster PowerBooster { get; set; }
public IEnumerable<IPart> GetChildParts()
{
yield return Switch;
yield return PowerBooster;
}
}
public class PowerCord : IPart
{
public IEnumerable<IPart> GetChildParts()
{
yield break;
}
}
Now we can easily build a part list generator that uses a recursive method to walk through the hierarchy and outputs the names of the parts.
public class PartListGenerator
{
public void OutpAllParts(IPart part, TextWriter textWriter)
{
OuputAllPartsByLevel(part, textWriter, 0);
}
private static void OuputAllPartsByLevel(IPart part, TextWriter textWriter, int level)
{
textWriter.WriteLine("{0}{1}", new string('t', level), part.GetType().Name);
foreach (var childPart in part.GetChildParts())
{
OuputAllPartsByLevel(childPart, textWriter, level + 1);
}
}
}
By running our CoffeeMachine through this class, we end up with something similar to the following output:
CoffeeMachine
FluxCapacitor
Switch
PowerBooster
PowerCord