Composite Pattern in C#
Tags: beginners, programming, tutorial, csharp
Published: 2022-09-04 19:22:52

_Originally posted [here](https://dfordebugging.wordpress.com/2022/09/04/composite-pattern-in-c/)_

The **Composite** is a structural design pattern that allows us to compose objects into tree structures and work with these structures as if they were individual objects.

The **Composite** represents part-whole hierarchies. This is a fancy way of saying that we can represent all parts of a hierarchy by reducing the pieces of said hierarchies down to common components.

You can find the example code of this post, on [GitHub](https://github.com/Kalkwst/DesignPatterns)

## Conceptualizing the Problem

Using the **Composite** pattern makes sense only when the core model of our application can be represented as a tree hierarchy.

Imagine that we are creating our unique flavour of a filesystem. We can have two types of objects: `Files` and `Folders`. A `Folder` can contain several `Files` as well as several other `Folders`. These folders can also hold some `Files` or even other `Folders`, and so on.

Say we decide to create a function that will calculate the size of a directory. A directory can contain a single `File` without any `Folders`, as well as `Folders` stuffed with `Files`...and other `Folders`. How would we determine the total size of such a directory?

We could try the direct approach: Move all the files out of their folders, go over each file and then calculate the total size. That would be doable in the real world; just remove the files and count the pages for example.

 However, in the digital world, this is not as simple as running a loop. We have to know the classes of `File`s and `Folder`s we are going through, the nesting level of the `Folders` and other nasty details beforehand. All of these details can make the direct approach either too awkward or simply impossible to implement.

The **Composite** pattern suggests that we work with `Files` and `Folders` through a common interface. This interface will declare a method for calculating the total size.

How would this method work? For a file, it'd simply return the file's size. For a folder, it'd go over each item the folder contains, ask its size and then return the total of the folder. If one of these items is another folder, that folder would also start going over its contents and so on, until the sizes of all inner components were calculated.

The greatest benefit of this approach is that we don't need to care about the concrete classes that compose the tree. We don't need to know whether the object is a simple product or a sophisticated box. We can treat them all the same via the common interface. When we call the method, the objects themselves pass the request down the tree.

## Structuring the Composite Pattern
In this basic implementation, the Composite pattern has 4 participants:

- **Component**: The **Component** interface describes operations that are common to both simple and complex elements of the tree.
- **Leaf**: The **Leaf** is a basic element of the tree that doesn't have child elements. Usually, leaf components end up having most of the business logic, since they don't have anyone to delegate the work to.
- **Container**: The **Container**, also known as *Composite* is an element that has child elements. A container doesn't know the concrete implementations of its children. It works with all the children only via the component interface. Upon receiving a request, a container delegate the work to its children, processes intermediate results and then returns the final result to the client.
- **Client**: The **Client** works with all elements through the component interface. As a result, the client can work in the same way with both simple or complex elements of the tree.

![Composite Pattern Class Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5eo3gtl3bkkyn4774qv9.PNG)

To demonstrate how the Composite pattern works, we are going to create our very own [Nuka-Cola Mixer](https://fallout.fandom.com/wiki/Nuka-mixer_station). 

For all those people out there, who are not fans of the [Fallout 4](https://fallout.fandom.com/wiki/Portal:Fallout_4) game, a Nuka Mixer Station is a machine that allows you to mix different Nuka-Cola flavours to create a new Nuka-Cola, similar to [these](https://www.coca-colafreestyle.com/) dispensers.

We can model how this dispenser works. The Nuka-Mixer can accept 5 types of components: *Regular Nuka Cola*, *Flavoured Nuka Cola*, *Variant Nuka Cola*, *Meds* and *Foodstuff*. In effect, this creates a hierarchy where "Soda" itself is the root component, the component types are the child Components, and the different flavours are the leaves.

A simplified version of this hierarchy might look like this:

![Nuka Cola Taxonomy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o6oye0hti0ngp0bmz4eh.PNG)

Let's model the hierarchy. For all possible flavours of soda that our machine can dispense, we need to know how many hit points each flavour provides. So, in our abstract class that represents all soft drinks, we need a property for `HitPoints`.

```csharp
namespace Composite
{
    /// <summary>
    /// Component abstract class
    /// </summary>
    public abstract class Component
    {
        public int HitPoints { get; set; }

        public List<Component> Flavors { get; set; }

        public Component(int hitPoints)
        {
            HitPoints = hitPoints;
            Flavors = new List<Component>();
        }

        /// <summary>
        /// Return all available flavours and their hitpoints
        /// </summary>
        public void DisplayHitPoints()
        {
            foreach(var drink in this.Flavors)
            {
                drink.DisplayHitPoints();
                this.HitPoints += drink.HitPoints;
            }

            Console.WriteLine($"{this.GetType().Name}: {this.HitPoints} hitpoints.");
        }
    }
}
```

Note the `DisplayHitPoints` method. Is a recursive method that will show the hitpoints of all components, and then display the total hitpoints of the composite object.

Next up, we need to implement several **Leaf** participants for the concrete Nuka-Cola flavors.

```csharp
namespace Composite.Leaves
{
    /// <summary>
    /// Leaf class
    /// </summary>
    public class NukaCola : Component
    {
        public NukaCola(int hitPoints) : base(hitPoints)
        {
        }
    }
}

namespace Composite.Leaves
{
    public class NukaGrape : Component
    {
        public NukaGrape(int hitPoints) : base(hitPoints)
        {
        }
    }
}

namespace Composite.Leaves
{
    public class NukaCherry : Component
    {
        public NukaCherry(int hitPoints) : base(hitPoints)
        {
        }
    }
}

namespace Composite.Leaves
{
    public class NukaWild : Component
    {
        public NukaWild(int hitPoints) : base(hitPoints)
        {
        }
    }
}
```

We now need to implement the **Composite** participant, which represents the hierarchy which has children. 

```csharp
namespace Composite.Composites
{
    public class NewkaCola : Component
    {
        public NewkaCola(int hitPoints) : base(hitPoints)
        {
        }
    }
}

namespace Composite.Composites
{
    public class NukaBerry : Component
    {
        public NukaBerry(int hitPoints) : base(hitPoints)
        {
        }
    }
}

namespace Composite.Composites
{
    public class NukaFancy : Component
    {
        public NukaFancy(int hitPoints) : base(hitPoints)
        {
        }
    }
}
```

The **Composite** classes are the same as the **Leaf** classes, and this is not an accident.

Finally, our `Main()` shows how we might initialize a new cola hierarchy with several flavours and then display all of the calories for each flavour:

```csharp
using Composite.Composites;
using Composite.Leaves;

var newkaCola = new NewkaCola(0);
newkaCola.Flavors.Add(new NukaCola(150));
newkaCola.Flavors.Add(new NukaCherry(150));

var nukaBerry = new NukaBerry(0);
nukaBerry.Flavors.Add(new NukaCola(150));
nukaBerry.Flavors.Add(new NukaCherry(150));
nukaBerry.Flavors.Add(new NukaGrape(100));

var nukaFancy = new NukaFancy(0);
nukaFancy.Flavors.Add(new NukaWild(50));
nukaFancy.Flavors.Add(new NukaCherry(150));

newkaCola.DisplayHitPoints();
Console.WriteLine("--------------------------");

nukaBerry.DisplayHitPoints();
Console.WriteLine("--------------------------");

nukaFancy.DisplayHitPoints();
```

The output of this method is:

![[composite-output.png]]
## Forms of the Composite Pattern
There are many different forms of the **Composite** pattern, but at a high level, they can be grouped into two categories: *Bill of Material* and *Taxonomy*.

### Bill of Material
A *Bill of Material* form captures the relationship that exists between a complex object and its parts. For example, a car could be said to be composed of a body and a chassis. The body is further made up of fenders, doors, a trunk, a hood etc. The chassis is further composed of a drive train and suspension.

If we are implementing a *Bill of Material* we will have many options when implementing its behaviour, each of which will have different implications.
- **Aggregating Behavior**: If we need to determine the weight of the car, for example, we need to aggregate the weights of all the subparts recursively. Often, this behaviour can be hidden from consuming client entities in the way **Component** nodes are implemented.
- **Best/Worst Case Behavior**: If we need to determine the overall health of the car, the rule might be that the car is in a healthy state, if and only if all of its parts are healthy. If any one part has a problem, we might say that the whole car has a problem. Thus, we can say that the car is the *worst case* of all its parts. Again, this behaviour can often be hidden from the consuming class in the way **Components** are implemented.
- **Investigatory**: If we need to determine something specific about a part, then we might need to allow the client to iterate through the parts looking for those that qualify. 

### Taxonomy
A *Taxonomy* form captures the logical relations that exist between more or less general types. The biological [classes](https://en.wikipedia.org/wiki/Class_(biology)) work this way. [Tetrapoda](https://en.wikipedia.org/wiki/Tetrapod) include the [Amphibia](https://en.wikipedia.org/wiki/Amphibian), the [Reptilia](https://en.wikipedia.org/wiki/Reptile) and the [Mammalia](https://en.wikipedia.org/wiki/Mammal). The Mammalia are further subdivided into the [Prototheria](https://en.wikipedia.org/wiki/Prototheria) and the [Theria](https://en.wikipedia.org/wiki/Theria) and so on.

When we are implementing a *Taxonomical* composite, our motivation is almost certainly to allow the client to traverse the structure, find information or classify an entity within the context of the existing structure.

### Iteration Options
The key decision to make when creating a Composite, which is whether or not to put methods into the target abstraction that allow for the client entity to traverse the Composite. These traversal methods create coupling between the client and the components, and should not be included unless they are needed.

In a *Bill of Material*, traversal methods may or not be needed, depending on the behaviour desired.

In a *Taxonomy*, traversal methods are almost always needed, since the purpose of the Composite is for the client to traverse it.

## Pros and Cons of Composite Pattern

|||
|:--|:--|
|✔ We can work with complex tree structures more conveniently. We can use polymorphism and recursion to our advantage.|❌It might be difficult to provide a common interface for classes whose functionality differs too much. In certain scenarios, we’d need to overgeneralize the component interface, making it harder to comprehend.|
|✔ We can introduce new element types into the application without breaking the existing code, which now works with the object tree. This respects the *Open-Closed Principle*.|❌ We need to take into account what form of composite we are working with. This will determine whether we are going to implement traversal methods for our composite.|

## Relations with Other Patterns
- The **Builder** pattern can be used for creating complex **Composite** trees because we can program its construction steps to work recursively.
- The **Chain of Responsibility** pattern is often used in conjunction with the **Composite** pattern. in this case, when a leaf component gets a request, it may pass it through the chain of all the parent components down to the object tree.
- We can use **Iterators** to traverse **Composite** trees.

## Final Thoughts

In this article, we have discussed what is the Composite pattern, when to use it and what are the pros and cons of using this design pattern. We then examined what are the different forms of the Composite and how the Composite pattern relates to other classic design patterns. 

It's worth noting that the Component pattern, along with the rest of the design patterns presented by the Gang of Four, is not a panacea or a be-all-end-all solution when designing an application. Once again it's up to the engineers to consider when to use a specific pattern. After all these patterns are useful when used as a precision tool, not a sledgehammer.