Manage Hierarchies with Composite Pattern

Introduction

The composite design pattern generalize a hierarchical structure. It helps deal with tree structure of information.

This make things easier for clients due to uniform way to work with individual items and for collections.

Lets start by stating that composite is not composition (composition is another useful software design approach. Decorator pattern utilizes composition).

In this post, we will learn some basic theory coving concepts, design, use cases and we will also see implementations of this pattern.

Concept

The basic concept is that components represents part or whole structure.

This is done by configuring your objects into tree structures. Once data is built this way, we can treat individual objects the same as a composite object.

Design

Core components of a composite pattern are:

  • Component
  • Leaf
  • Composite

Root of a tree start with a component.

Components are one of two things:

  • Leaf
  • Composite of objects

Composite knows about child objects.

UML

Following is the UML diagram of composite pattern:

Next, lets see some example of implementing this pattern. Note, that implementation may differ based on actual use case. Here I will be using very basic examples of this pattern.

I will be using C#, but you can implement it in similar way in other programming languages.

All the source code is available from this git repository.

Example (Structural)

Lets see a very basic example. You can check the source code from the git repository.

Here is the C# code for the structural example:

Here is example of how the structure is built and operations are performed:

The output of the operations:

Example (Menu <–> Menu-Item)

Site menus are another example where composite pattern can help us deal with this structure very easily. Menus can have menu-items or they can have sub-menus which then can contains more sub-menus and/or menu-items.

Following the same structure from previous example, here is the code for application Menu and sub menus and menu-items:

Both Menu and MenuItem implements same abstraction (MenuComponent).

Following is the usage code:

And here is the output of the execution:

A small enhancement of this code could be to show the parent-menu URL as well when displaying child menu-item. However, I’ll not implement it here and you can do it as an exercise.

Let’s see another example of composite pattern.

Example (Order <–> Order-Item)

For this example, lets see how the existing code is setup:

It is a very common Order and Order-item relationship. An order can contains one or more Order-Items. Typically there are multiple orders for a customer in real life.

Here is the calling code which create an Order for a customer:

here is the output of running this code:

(Note: In sample code, these classes are renamed to OrderOld and OrderItemOld due to later updates.)

New Requirement (Merging Order)

Some customers might place more than one order. e.g. they place a 2nd order before their first order has shipped and if that happens, we would like to merge orders together.

(Now merging is a common requirement, you can merge bills, consignments, invoices etc. Similar to that on the opposite side, you can split a job into multiple smaller jobs, or a task into sub tasks, an organization into departments etc.) However, for example here, we will see how composite pattern can help us implementing this requirement (i.e. merging orders).

Solution-1 (MultipleOrder class)

Onaway to built this solution is by introducing another class “MultipleOrder” which aggregates multiple orders in the same way that Order aggregates OrderItem.

This is not a good design. What if, we need to aggregate multiple-Orders? so not a good solution.

Solution-2

The most obvious solution, which many will go as a first choice, is to just compose multiple orders by taking them apart and putting them back together.

Following example does that:

This looks like a simple solution. But its not that convincing. It involves copying stuff from one object to the other. Because objects tend to grow complicated with time and code to copy data process becomes awkward and prone to errors.

This is not a terrible solution but may be we can find something, which doesn’t copy stuff.

Solution -3 (Composite Pattern)

Lets introduce composite pattern to the solution, so we can treat Order and Order-item(collection) in same way.

To that happen, we need to be able to treat object of two classes in the same way in the collection and also in the code. We can do this by having a same interface (abstraction).

Here is the implementation using composite pattern:

Now Order and OrderItem both implement the same abstraction and can be treated in a similar way. This way you can put OrderItem togather in an Order or also can have Order inside another Order. You can check the source code for implementation details.

Following is the tree structure and operation:

As you can see that now we can treat collections and individual items in same way. Client just look at both leaves and composites as components and that is the composite design pattern.

Following is the execution result:

Composite and Hierarchies

Composite is a pattern, that generates hierarchies. Some of the objects in the hierarchy are atomic, they are leaves. Others are composite, they are aggregates of other objects and these objects can themselves be either leaves or composites.

So we can structure hierarchy into as many layers as we want. Another classic example of composite pattern is file-system. You have files, which are leaves of the system, and you have directories, which are aggregates. They can contain files or other directories. All these objects share a common interface (lets call it FileSystemItem).

(Note, this pattern doesn’t make sense if you don’t have useful common that is shared by composite and leaves)

Summary

Composite design pattern is very useful in software design and it can help reduce complexity in many situations. In this post, we learned some theory and saw few implementations of this pattern.

You can download the source code form this git repository.

Let me know if you have some comments or questions. Till next time, Happy Coding.

My Recent Books