Design Pattern articles in this series are listed below:

Design Patterns - An Overview
Design Patterns – Using the Strategy Pattern in C#
Design Patterns – Using the Singleton Pattern in C#
Design Patterns – Using the Adapter Pattern in C#
Design Patterns - Using the Facade Pattern in C#
Design Patterns - Using the Composite Pattern in C#
Design Patterns - Using the Decorator Pattern in C#
Design Patterns - Using the Abstract Factory Pattern in C#
Design Patterns – Using the Builder Pattern in C#
Design Patterns - Using the Observer Pattern in C# (Events and Delegates)
Design Patterns – Using the Chain of Responsibility Pattern in C#
Design Patterns – Using the State Pattern in C#
Design Patterns – Which to use When? Take the Quiz!

What is a Composite Pattern?

Composite Pattern enables a client to treat a single entity and a collection of entities in the same way. Frequently, developers create systems in which a component may be an object or a collection of objects. For example, an application that gathers metrics on the size of the files/folders in a file system would like to treat the folder and the file in the same way. A folder is either empty or composed of one or more files. The size of a folder is the size of the individual files that make the folder and the size of the file is the size of that individual file itself. The Composite Pattern is designed to accommodate such a requirement.

When do you know when to use a Composite Pattern? Consider using a Composite pattern when you can represent your problem in a tree structure. A tree is a data structure in which a node has zero or more child nodes. A node that has children is known as the child’s parent node and nodes at the bottommost level are called leaf nodes.

How is the Composite Pattern implemented?

Let me illustrate how the Composite Pattern is implemented with an example. Let’s assume we are working on an application that calculates the cost associated with different teams in a company. The organizational chart of this company is illustrated in the figure below. At the top of the org chart is the Chief Executive Officer (CEO) who has 2 Vice Presidents reporting to him. The VP of Technology has 2 developers and since the company is still in the growth mode, the VP of Sales does not have anyone reporting to him.

CompositePattern

The application we are developing should calculate the “cost” incurred in different teams. The cost is calculated by the summation of the salary of the department head and the salaries of employees that report to the department head. For example, the cost of the Technology team is the sum of salary of the VP-Technology, Developer1 and Developer2.

The Composite Pattern is perfect for this application as we would like to treat the object (say Developer1) and the collection of objects (say VP-Technology) in the same manner.

The Composite Pattern is made of the following entities:

1. IComponent: An interface that defines operations for objects in the composition.

2. Component: A class that implements the operations to single objects

3. Composite: A class that implements the operations to the collection of objects

4. Client: A class that uses the IComponent interface to operate on components and composite.

Let’s take a look at the code for the IComponent first.

namespace CompositePattern
{
    public interface IComponent
    {
        string Title { get; set; }
        decimal Salary { get; set; }
        void Add(IComponent c);
        void GetCost(ref decimal salary);
    }
}

The interface has the common properties for both the Component and the Composite. In our example, all company roles are identified by the Title and the Salary. The Add method adds an employee to the team. It’s important to note that roles that are leaves in the organizational chart (Developers) do not have anyone reporting to them, so we should not be able to add anyone to the Developer node. The Component class implementation is as shown below.

namespace CompositePattern
{
    public class Component : IComponent
    {
        public string Title { get; set; }
        public decimal Salary { get; set; }

        public Component(string Title, decimal Salary)
        {
            this.Title = Title;
            this.Salary = Salary;
        }

        public void Add(IComponent c)
        {
            Console.WriteLine("Cannot add to the leaf!");
        }

        public void GetCost(ref decimal salary)
        {
            salary += Salary;
        }
    }
}

Since we cannot add to a leaf, the Add method simply writes an error statement to the Console.

The Composite class implementation is as shown below.

namespace CompositePattern
{
    public class Composite : IComponent
    {
        private List<IComponent> _listEmployees;

        public string Title { get; set; }
        public decimal Salary { get; set; }

        public Composite(string Title, decimal Salary)
        {
            this.Title = Title;
            this.Salary = Salary;
            _listEmployees = new List<IComponent>();
        }

        public void Add(IComponent comp)
        {
            _listEmployees.Add(comp);
        }

        public void GetCost(ref decimal salary)
        {
            salary += this.Salary;

            foreach (IComponent component in this._listEmployees)
            {
                component.GetCost(ref salary);
            }
        }
    }
}

The Composite class has a List collection that it uses to add components to (In the Add method). The GetCost method should calculate the summation of the salaries and this is done by recursion.

The Client will operate with IComponent interface. The code snippet below creates the organizational chart as depicted in the figure earlier. It then calls the GetCost methods at the CEO and the VP-Development level.

namespace CompositePattern
{
    class Program
    {
        static void Main(string[] args)
        {
            decimal costCEO = 0.0M;
            decimal costVPD = 0.0M;

            //Create CEO Node
            IComponent compCEO = new Composite("CEO", 500000);

            //Create VP-Development and Developer nodes
            IComponent compVPDev = new Composite("VP-Development", 250000);

            IComponent compDev1 = new Component("Developer1", 75000);
            IComponent compDev2 = new Component("Developer2", 50000);

            compVPDev.Add(compDev1);
            compVPDev.Add(compDev2);

            //Create VP-Sales node
            IComponent compVPSales = new Component("VP-Sales", 300000);

            compCEO.Add(compVPDev);
            compCEO.Add(compVPSales);

            //Get the cost incurred at the CEO level
            compCEO.GetCost(ref costCEO);

            Console.WriteLine(String.Format("The Cost incurred at the CEO            level is {0:c} ", costCEO));

            //Get the cost incurred at the VP-Development level
            compVPDev.GetCost(ref costVPD);
            Console.WriteLine(String.Format("The Cost incurred at the VP-Development level is {0:c} ", costVPD));
        }
    }
}

The output generated is shown below

image

The cost incurred at the CEO level is $1,175,000 which is the summation of salaries of CEO, VP-Development, Developer1, Developer2 and VP-Sales.

The cost incurred at the VP-Development level is $375,000 which is the summation of salaries of VP-Development, Developer1 and Developer2

Physical Model – Class Diagram

image

Conclusion

The Composite Pattern is suitable for solving problems that can be represented by a tree datastructure. It lets the client treat the entity (individual component) and the collection of entities (Composite) in the same way.

Stay tuned for more design pattern related articles coming soon on this website. Subscribe to the RSS feed or follow me on Twitter to be the first one to be notified of new posts.

Retweetkick it on DotNetKicks.com