Back to: Design Patterns in C# With Real-Time Examples
Composite Design Pattern in C# with Examples
In this article, I am going to discuss the Composite Design Pattern in C# with Examples. Please read our previous article where we discussed the Bridge Design Pattern in C# with Examples. The Composite Design Pattern falls under the category of Structural Design Pattern. As part of this article, we are going to discuss the following pointers.
- What is the Composite Design Pattern in C#?
- Understanding the Composite Design Pattern in C# with Real-time Examples.
- Implementing the Composite Design Pattern in C#.
- Understanding the components involved in the Composite Design Pattern.
- When to use the Composite Design Pattern in real-time applications?
What is the Composite Design Pattern in C#?
As per the Gang of Four definitions, the Composite Design Pattern states that “Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly”.
The Composite Design Pattern allows us to compose one whole object from one or more individual objects to represent a part-whole hierarchy. The Composite Design Pattern represents Part-Whole hierarchies of objects. That means the client can access the individual objects or the composition of objects in a uniform manner.
In simple words, we can say that the Composite Design Pattern composes the objects in the form of a tree structure to represent part as well as a whole hierarchy. This design pattern is used when we need to treat a group of objects in a similar way as a single object. If this is not clear at the moment, then don’t worry we will try to understand this with an example.
Example to Understand Composite Design Pattern in C#:
The term composite means a thing made of several parts or elements. Let us understand the Composite Design Pattern in C# with one Real-Time Example. Here we want to assemble a computer. As we know a computer is made of several parts or elements integrated together as shown in the below image.
As shown in the above image, everything is an object. So, here, Computer, Cabinet, Peripherals, Hard Disk, Mother Board, Mouse, Keyboard, CPU, RAM, etc. all are objects.
A composite object is an object which contains other objects. The point that you need to remember is a composite component may also contain other composite objects. The object which does not contain any other objects is simply treated as a leaf object.
So, in our example, Computer, Cabinet, Peripherals, and Mother Boards are composite objects while Hard Disk, CPU, RAM, Mouse, and Keyboard are the leaf object which is shown in the below diagram.
All the above objects are of the same type i.e. Electronics type. For example, if we talk about a computer it is an electronic device. If we talk about the motherboard, it is an electronic device and similarly, if we talk about Mouse, it is also an electronic device. That means they follow the same structure and features. For example, all the above objects have a price. So, you may ask the price of a Keyboard or Mouse or Motherboard even though the price of a computer.
When you ask the price of the Keyboard, it should show you the price of the Keyboard. But when you are asking the Price for the motherboard, then it needs to display the Price of RAM and CPU. Similarly, when you are asking the price of the computer, then it needs to display all the prices.
The Composite Design Pattern is a tree structure having composite objects and leaf objects. The fundamental idea is if you perform some operation on the leaf object then the same operation should also be performed on the composite objects. For example, if I am able to get the price of a Mouse, then I should be able to get the Price of Peripherals (here, it should display the price of both the Mouse and Keyboard), and even I should be able to get the Price of the Computer object. If you want to implement something like this, then you need to use the Composite Design Pattern.
Implementation of Composite Design Pattern in C#
Let us implement the above-discussed example using Composite Design Pattern in C#. First, we will implement the above example using Composite Design Pattern in C# and then we will discuss the UML Diagram of the Composite Design Pattern by comparing it with our example.
Step1: Creating IComponent Interface
Create an interface with the name IComponent.cs and then copy and paste the following code into it. The following IComponent base interface declares the common operations for both simple and complex objects i.e. the operations which are going to be common for both Leaf Objects and Composite Objects are going to be declared here. For our example, we need to show the price of a Leaf Component as well as we also need to show the Price of Composite Components. So, we need to declare that method here. As you can see in the below code, we have declared the DisplayPrice method which is going to be implemented by both Leaf Object and Composite Object.
namespace CompositeDesignPattern { // The base Component class declares the common operations for both simple and complex objects. public interface IComponent { void DisplayPrice(); } }
Step2: Creating Leaf Class
The Leaf class represents the end objects i.e. the actual object which does the actual work. A leaf can’t have any children. So, create a class file with the name Leaf.cs and then copy and paste the following code into it. This class implements the IComponent interface and provides implementations for the DisplayPrice method. As part of this class, we are creating two properties to display the component name and price and we are initializing these two properties using the parameterized constructor of the class. And finally, we are displaying these two values in the DisplayPrice method.
using System; namespace CompositeDesignPattern { // The Leaf class represents the end objects. // A leaf can't have any children. // The Leaf object is the Object which does the actual work public class Leaf : IComponent { public int Price { get; set; } public string Name { get; set; } public Leaf(string name, int price) { this.Price = price; this.Name = name; } public void DisplayPrice() { Console.WriteLine($"\tComponent Name: {Name} and Price: {Price}"); } } }
Step3: Creating Composite Class
The Composite class represents the composite components that have children. The Composite objects delegate the actual work to their children and then combine the result. So, create a class file with the name Composite.cs and then copy and paste the following code into it. As this class is going to be our composite class, so we are creating a variable to hold the component name and another variable to hold its child components. Again we are initializing the name property using the class constructor. Using the AddComponent() method we are adding the child components inside the components variable. This class also implements the IComponent interface and as part of the DisplayPrice() method, first, we are calling all the leaf object DisplayPrice method of the Composite Object using a for-each loop. The following example code is self-explained, so please go through the comment lines for a better understanding.
using System.Collections.Generic; namespace CompositeDesignPattern { // The Composite class represents the complex components that have children. // The Composite objects delegate the actual work to their children and then combine the result. public class Composite : IComponent { public string Name { get; set; } //The Object is used to hold all the child components of a composite components List<IComponent> components = new List<IComponent>(); //The Constructor takes the Composite name as the input parameter public Composite(string name) { this.Name = name; } //The following Method is used to add Child Components inside the Composite Component public void AddComponent(IComponent component) { components.Add(component); } //Display the Price of Composite Components public void DisplayPrice() { foreach (var item in components) { //Delegates the work to the actual leaf object or child components item.DisplayPrice(); } } } }
Step4: Client Program
The client code works with all of the components (Both Leaf and Composite) via the base interface i.e. IComponent i.e. the class that implements the IComponent Interface. So, please modify the Main method of the Program class as shown below. Here, we are creating the tree structure and then show the respective component price by calling the DisplayPrice method. Here, you can see, we are creating leaf objects, we are creating composite objects, and then calling the DisplayPrice method on both Leaf objects as well as Composite objects. The following example code is self-explained, so please go through the comment lines for a better understanding.
using System; namespace CompositeDesignPattern { public class Program { static void Main(string[] args) { // The client code works with all of the components (Both Leaf and Composite) via the base interface i.e. IComponent. // IComponent means the class that implements the IComponent Interface //Creating Leaf Objects or you can say child objects IComponent hardDisk = new Leaf("Hard Disk", 2000); IComponent ram = new Leaf("RAM", 3000); IComponent cpu = new Leaf("CPU", 2000); IComponent mouse = new Leaf("Mouse", 2000); IComponent keyboard = new Leaf("Keyboard", 2000); //Creating Composite Objects Composite motherBoard = new Composite("MotherBoard"); Composite cabinet = new Composite("Cabinet"); Composite peripherals = new Composite("Peripherals"); Composite computer = new Composite("Computer"); //Creating Tree Structure i.e. Adding Child Components inside the Composite Component //Adding CPU and RAM in Mother Board motherBoard.AddComponent(cpu); motherBoard.AddComponent(ram); //Adding Mother Board and Hard Disk in Cabinet cabinet.AddComponent(motherBoard); cabinet.AddComponent(hardDisk); //Adding Mouse and Keyboard in peripherals peripherals.AddComponent(mouse); peripherals.AddComponent(keyboard); //Adding Cabinet and Peripherals in Computer computer.AddComponent(cabinet); computer.AddComponent(peripherals); //To Display the Price of the Computer i.e. it will display the Price of all components Console.WriteLine("Price of Computer Composite Components"); computer.DisplayPrice(); //To display the Price of the Keyboard Console.WriteLine("\nPrice of Keyboard Child or Leaf Component:"); keyboard.DisplayPrice(); //To display the Price of the Cabinet Console.WriteLine("\nPrice of Cabinet Composite Component:"); cabinet.DisplayPrice(); Console.Read(); } } }
Output:
Understanding the Class Diagram or UML Diagram of the Composite Design Pattern:
The Composite Design Pattern treats each node in two ways i.e. Composite or Leaf. Composite means it can have other objects (both Composite or Leaf) below it. On the other hand, a Leaf node means there are no objects below it. Please have a look at the following diagram to understand the Class Diagram or UML Diagram of the Composite Design Pattern and understand the different components involved in the Composite Design Pattern.
There are four participants involved in the Composite Design Pattern. They are as follows:
- Component: This is going to be an abstract class or interface containing the members that will be implemented by both Leaf and Composite Classes. If required then it can also implement some of the behavior that is common to all objects in the composition and in that case we need to create the Component as an abstract class. That means the abstract class or interface acts as the base class for all the objects within the hierarchy. In our example, it is the IComponent interface.
- Leaf: This is going to be a class to represent the leaf behavior in the composition. In our example, it is the Leaf class. A leaf object does not have any children.
- Composite: The Composite defines the behavior of the Composite Components. The component having children. The children can be another composite component or can be a leaf component. In our example, it is the Composite class. This class defines the necessary operations that can be performed on the child components, i.e. Add, Remove, Get, Find, etc. methods.
- Client: The Client is the class that manipulates objects in the composition through the Component interface i.e. the child classes that implements the Component interface or abstract class. In our example, the Main method of the Program class is going to be the client.
When do we need to use the Composite Design Pattern in C# Real-Time Applications?
We need to use the Composite Design Pattern in C# Real-time Applications, when
- We want to represent part-whole hierarchies of objects.
- We want the clients to ignore the difference between the compositions of objects and individual objects.
In the next article, I am going to discuss the Real-Time Example of the Composite Design Pattern in C#. Here, in this article, I try to explain the Composite Design Pattern in C# with Examples. I hope, now you understood the need and use of the Composite Design Pattern in C# with Examples.