Welcome to the Design Patterns for Beginners article aeries. In this article we will be learning how to implement a Composite Design Pattern in applications. From the past few articles I have been discussing various design patterns. If you are rely passionate about learning design pattern then please visit my previous articles:
In today's session we will learn about the Composite Design Pattern and we will discuss a few scenarios where the Composite Design Pattern may rescue you. At first we will discuss why the Composite Design Pattern is needed.
What the Composite Design Pattern Is
The Composite Design Pattern always forms a tree structure with the objects, where each root element contains sub nodes called child nodes and child nodes contain leaf nodes (last label node). Leaf nodes do not contain any elements. Now, in this object hierarchy we can point any node and from this node we can traverse all other nodes.
For example, think about an employee stricture of an organization. We can easily represent it by a tree structure and if we start from the CEO (the root of the organization) then we can reach leaf employees by traversing through the middle-level managers.
Take another example of a Composite Design Pattern. Think about the folder structure of your computer. Each drive contains many folders and each folder contains many subfolders and each subfolder contains many files. Here the files are nothing but the leaf nodes. A node from any drive partition you may traverse down to any file by a couple of mouse clicks.
Why composite pattern?
The Composite Design Pattern is useful when individual objects as well as a group of those kinds of objects are treated uniformly.
Hmm.., bookish definition. Let's think of a scenario where we want to draw a few shapes in the same canvas. And we will draw all the components in the same way (by calling a respective function). We will try to implement it with a small working example. Have a look at the following code:
- using System;
- using System.Collections;
- using System.Globalization;
- using System.Data.SqlClient;
- using System.Data;
- namespace Test1
- {
- interface IDraw
- {
- void Draw();
- }
- class Circle : IDraw
- {
- public void Draw()
- {
- Console.WriteLine("I am Circl");
- }
- }
- class Square: IDraw
- {
- public void Draw()
- {
- Console.WriteLine("I am Square");
- }
- }
- class Oval : IDraw
- {
- public void Draw()
- {
- Console.WriteLine("I am Oval");
- }
- }
- class Program
- {
- static void Main(string[] args)
- {
- ArrayList objList = new ArrayList();
- IDraw objcircl = new Circle();
- IDraw objSquare = new Square();
- IDraw objOval = new Oval();
- objList.Add(objcircl);
- objList.Add(objSquare);
- objList.Add(objOval);
- foreach (IDraw obj in objList)
- {
- obj.Draw();
- }
- Console.ReadLine();
- }
- }
- }
Here, we have created a draw interface and three classes are deriving from them. Now, try to match this class hierarchy with the basic structure of the Composite Design Pattern. Here the IDraw interface is the root node and since three classes are derived from it (here implemented) and all of them are child nodes.
Each and every child class contains the same function definition and that's why we are able to call the Draw() function from each class within the for loop.
Here is sample output of this example:
In the next example we will implement one organization designation scenario in the Composite Design Pattern. We will assume that it is a small organization where employees are categories only in three levels.
CEO
Head Manager
Area Manager
Now, in this example we have implemented the following tree structure.
Since this is the tree structure we can reach any leaf node from any non-leaf node. For example if we start from the root (CEO) node then by traversing the HM (Head Manager) nodes we can easily reach an Area Manager node.
We will consider each node as a class in a sample example. Each class will also contain a common function called Designation(). In the following example we will start from a leaf node and will reach to the root node. Have a look at the following implementation.
- using System;
- using System.Collections;
- using System.Globalization;
- using System.Data.SqlClient;
- using System.Data;
- using System.Collections.Generic;
- namespace Test1
- {
- interface IEmployee
- {
- void Designation();
- }
- class CEO :IEmployee
- {
- public virtual void Designation()
- {
- Console.WriteLine("I am sourav.CEO of Company");
- }
- }
- class HeadManager_1:CEO,IEmployee
- {
- public override void Designation()
- {
- Console.WriteLine("I am Rick. My Boss is sourav");
- }
- }
- class HeadManager_2 : CEO,IEmployee
- {
- public override void Designation()
- {
- Console.WriteLine("I am Martin. My Boss is sourav");
- }
- }
- class AreaManager:HeadManager_1,IEmployee
- {
- public new void Designation()
- {
- Console.WriteLine("I am Mack. My Boss is Rick");
- }
- }
- class Program
- {
- static void Main(string[] args)
- {
- IEmployee AreaManager = new AreaManager();
- IEmployee Hm_1 = new HeadManager_1();
- IEmployee CEO = new CEO();
- List<IEmployee> objEmployee = new List<IEmployee>();
- objEmployee.Add(AreaManager);
- objEmployee.Add(Hm_1);
- objEmployee.Add(CEO);
- foreach (IEmployee O in objEmployee)
- {
- O.Designation();
- }
- Console.ReadLine();
- }
- }
- }
Here is a sample example.
Conclusion
In this article we have seen how to implement a Composite Design Pattern in C#. Hope you have enjoyed it.