Blog / Design Patterns
The Composite Design Pattern in C# and .Net
  • Dec 22, 2020
  • 77
  • 97

The Composite Design Pattern is the third in the Gamma's Structural Category that I want to share in this post. Let's see what is this design pattern and how to implement it.

Note: Code can be downloaded at my Github.


Advertisement
 


1. What is the Composite Design Pattern?

The Composite Design Pattern has the peculiar goal of allowing us to treat individual components and aggregate objects in the same manner. The intent of a composite is to "compose" objects into tree structures to represent part-whole hierarchies.

Composite is a structural design pattern that lets you compose objects into tree structures and then work with these structures as if they were individual objects.


2. When to implement the Composite Design Pattern?

When the core model of your application has a tree structure, it's time to consider the Composite Design Pattern.

There are many examples of a tree structure in applications. For instance, if you have a e-commerce website which utilizes an ordering system that uses Product and Box classes. One order can contain one ore more boxes. Also, a box can contain one or more smaller boxes or products. In the smaller boxes, they can also contain other boxes or products as well. 

Another example is a supervisory chain of command, which represents the manager-employee hierarchy in a work place. You are reporting directly to your manager and your manager may have his or her manager who is also reporting to their higher level managers. Also, you may be a manager of someone else.

So, what is the problem here? The problem is we have different classes (Box and Product in the first example and different types of employee in the second example) which are difficult to process in one looping round. We need to come up with a way to treat the different classes uniformly. The Composite Design Pattern can help to achieve that goal.

3. How to implement the Composite Design Pattern?

Let's take the supervisory hierarchy example above to implement the Composite Design Pattern. In your company, there are 3 types of Employee: Fulltime, Contractor, and Intern which have different characteristics. 

Step 1: Create a Component interface

public interface IEmployeeComponent
{
    void Add(Employee e);
    void Remove(Employee e);
    void Display(int depth);
}

Step 2: Create a Composite class

	
public abstract class Employee : IEmployeeComponent
{
    public string Name { get; set; }
    public string Title { get; set; }
 
    public List<Employee> _children { get; set; } = new List<Employee>();
 
    public Employee(string name, string title)
    {
        Name = name;
        Title = title;
    }
 
    public abstract double GetMonthlySalary();
 
    public void Add(Employee e)
    {
        _children.Add(e);
    }
 
    public void Remove(Employee e)
    {
        _children.Remove(e);
    }
 
    public void Display(int depth)
    {
        Console.WriteLine(new String('-', depth) + $"{Name} " +
            $"is a {Title} who earns " +
            $"{GetMonthlySalary().ToString("F2")} monthly.");
 
        // Recursively display child nodes
 
        foreach (Employee emp in _children)
        {
            emp.Display(depth + 2);
        }
    }
}

Step 3: Create subclasses for different types of Employee

public class Fulltime : Employee
{
    public double AnnualRate { get; set; }
 
    public Fulltime(string name, string title, double annualRate)
        : base(name, title)
    {
        AnnualRate = annualRate;
    }
 
    public override double GetMonthlySalary()
    {
        return AnnualRate / 12;
    }
}
 
public class Contractor : Employee
{
    public double HourlyRate { get; set; }
 
    public Contractor(string name, string title, double hourlyRate)
        : base(name, title)
    {
        HourlyRate = hourlyRate;
    }
 
    public override double GetMonthlySalary()
    {
        return HourlyRate * 8 * 5 * 4;
    }
}
 
public class Intern : Employee
{
    public double HourlyRate { get; set; }
    public double WorkingDaysPerWeek { get; set; }
    public double HoursPerDay { get; set; }
 
    public Intern(string name, string title, double hourlyRate, double workingDaysPerWeek, double hoursPerDay)
        : base(name, title)
    {
        HourlyRate = hourlyRate;
        WorkingDaysPerWeek = workingDaysPerWeek;
        HoursPerDay = hoursPerDay;
    }
 
    public override double GetMonthlySalary()
    {
        return HourlyRate * HoursPerDay * WorkingDaysPerWeek * 4;
    }
}

So, now you can create a tree of supervisory hierarchy and print it. 

class Program
{
    static void Main(string[] args)
    {
        Employee ftEmp0 = new Fulltime("Hoang", "Fulltime Employee", 145000.00);
 
        Console.WriteLine();
        Console.WriteLine("---Add Employee Then Display---");
 
        Employee ftEmp1 = new Fulltime("Rachel", "Fulltime Employee", 90000.00);
        Employee ctEmp1 = new Contractor("Lu", "Contractor Employee", 72.00);
        Employee iEmp1 = new Intern("Shawn", "Intern Employee", 15.00, 3, 7);
 
        ftEmp0.Add(ftEmp1);
        ftEmp0.Add(ctEmp1);
        ftEmp0.Add(iEmp1);
 
        Employee ftEmp2 = new Fulltime("Yong", "Fulltime Employee", 82000.00);
        Employee ctEmp2 = new Contractor("Lucas", "Contractor Employee", 45.00);
 
        ftEmp1.Add(ctEmp2);
        ctEmp1.Add(ftEmp2);
 
        ftEmp0.Display(1);
 
        Console.WriteLine();
        Console.WriteLine("---Remove Employee Then Display---");
 
        ftEmp0.Remove(ftEmp1);
 
        ftEmp0.Display(1);
    }
}

4. Conclusion

With the help of the Composite Design Pattern, it's easier to build a structure for a group of complex classes and treat them uniformly. I hope this tutorial is helpful! Please let me know your thoughts and questions in the comment section below. See you next time!


If you have a Website or a Web API developed by using .Net Core and looking for a way to publish your applications, this post will explain how to do it using GoDaddy Windows Hosting.Note: at this mome ...

Search text in Stored Procedure in SQL SELECT DISTINCT o.name AS Object_Name, o.type_desc FROM sys.sql_modules m INNER JOIN sys.objects o ON m.object_id = o ...

Using cherry-pick to select specific commits for your Pull Request.1. Create a new branch based on the target of the Pull Requestgit branch cherry-branch origin/master2. Switch to a new branchgit chec ...

After deployment Angular and API on IIS, it's working fine unless I refresh the page. Once refreshed, the web encountered 404 error. In this article, I will explain how to resolve this.Since Angular i ...

There are some benefits of keeping both UI and API parts in the same place for small projects. In this article, I will explain how I did to deploy Angular Web and ASP .Net Core API in the same folder ...

I got CORS error after publishing my API and Angular app to IIS even though CORS is enabled and the origins of the Angular app is added. Below is how I resolved this issue.Just simple, make sure you s ...

1. The Situation:Error Message:&nbsp;Pulse Secure Application failed to load Java. Please install correct JRE version.Description: This issue happens when I'm using a M1 Mac with a correct version of ...

Accelerated Mobile Pages (AMP)&nbsp;focuses on delivering static content from publishers as quickly as possible and possibly rewards early adopters with a boost in rank. Let's see how to implement it ...

Below is how to decrypt/convert a Hex string value into text using VB.Net:Decrypting Hex string value to string in VB.Net Function HexToString(ByVal hex As String) As String Dim text As New Sy ...