Implementing the Composite design pattern in C#

This pattern represents part-whole hierarchies of objects such that the consumers or the clients can treat the objects and also the compositions of objects in a uniform manner

compositepattern
Joydip Kanjilal

Design patterns are tested, proven solutions to recurring problems that are often encountered in software designs. When used judiciously, they can help you to solve complex design problems easily.

The GOF (Gang of Four) design patterns are categorized as Creational, Structural, or Behavioral. The Composite design pattern falls under the Structural category and helps you to implement a composite structure of objects such that the clients can treat the objects and also the compositions in a uniform manner.

What is the Composite design pattern all about?

The Composite design pattern enables you to compose one whole object from one or more individual objects to represent a part-whole hierarchy. As an example, we can build a tree (a composite structure) using multiple objects (also called the leaves of the tree). In essence, the Composite design pattern enables you to isolate an abstraction from the actual implementation.

The participants

The participants in the Composite design pattern include the following:

  • Component -- This is represented by either an abstract class or an interface and serves as the base type for all objects in the hierarchy
  • CompositeElement -- This is represented using a concrete class that defines the necessary operations that can be performed on the child components, i.e., Add, Remove, Get, Find, etc. methods.
  • Leaf -- This represents a leaf component, and is defined using a class that doesn't have any subclass

Consider the following class, named Employee. This is an abstract class and represents the "Component" in this design. It contains abstract methods to add, an employee, remove an employee and also get data related to one or more employees.

 public abstract class Employee

    {

        protected string name;

        protected double salary;

        public Employee(string name, double salary)

        {

            this.name = name;

            this.salary = salary;

        }

        public abstract void Add(Employee employee);

        public abstract void Remove(Employee employee);

        public abstract string GetData();

    }

The abstract class Employee also contains an argument constructor to assign values to the name and salary variables.

The next class in our design is named "TeamLead," and it represents the "Composite" type in our design, extends the Employee class, and provides the definition for the abstract methods.

public class TeamLead : Employee

    {

        List<Employee> lstEmployee = new List<Employee>();

        public TeamLead(string name, double salary) : base(name, salary) { }

        public override void Add(Employee employee)

        {

            lstEmployee.Add(employee);

        }

        public override void Remove(Employee employee)

        {

            lstEmployee.Remove(employee);

        }

        public override string GetData()

        {

            StringBuilder sbEmployee = new StringBuilder();

             foreach (Employee emp in lstEmployee)

            {

                sbEmployee.Append(emp.GetData()+ "\n");

            } 

            return sbEmployee.ToString();

        }

    }

The last class in our design is the TeamMember class that represents the leaf node in the composite structure. Here's how this class looks:

public class TeamMember : Employee

    {

        public TeamMember(string name, double salary) : base(name, salary) { }

        public override void Add(Employee employee)

        {

            //Operation not permitted since this is a leaf node.

        }

        public override void Remove(Employee employee)

        {

            //Operation not permitted since this is a leaf node.

        }

        public override string GetData()

        {

            return "Name: "+ name + "\tSalary: "+salary.ToString("N2");

        }

    }

A leaf node in a composite structure doesn’t have any children, right? Note that since the TeamMember class represents a leaf node in the composite structure, there are no implementations of the “Add” or the “Remove” methods in this class.

The following code snippet illustrates how you can create instances of the Employee class, add them to the employee’s collection and then display the data in the console window.

static void Main(string[] args)

    {

      Employee employeeA = new TeamMember("Joydip Kanjilal", 20000);

      Employee employeeB = new TeamMember("Samuel Jones", 45000);

      Employee teamLead = new TeamLead("Steve Smith", 75000);

      teamLead.Add(employeeA);

      teamLead.Add(employeeB);

      Console.WriteLine(teamLead.GetData());

      Console.Read();

    }

When you execute the above code snippet, the details of the two employees those are part of Steve's team would be displayed in the console window. You can learn more on the Composite design pattern here.

Copyright © 2017 IDG Communications, Inc.