© Vaskaran Sarcar 2020
V. SarcarDesign Patterns in C#https://doi.org/10.1007/978-1-4842-6062-3_11

11. Composite Pattern

Vaskaran Sarcar1 
(1)
Garia, Kolkata, West Bengal, India
 

This chapter covers the Composite pattern.

GoF Definition

Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.

Concept

Consider a shop that sells different kinds of dry fruit, such as cashews, dates, and walnuts. Each of these items has a certain price. Let’s assume that you can purchase any of these individual items, or you can purchase “gift packs” (or boxed items), which are composed of different dry fruit items. In this case, the cost of a packet is the sum of its component parts. The Composite pattern is useful in a similar situation, in which you treat both the individual parts and the combination of the parts in the same way so that you can process them uniformly.

This pattern is useful to represent part-whole hierarchies of objects. In object-oriented programming, a composite is an object with a composition of one or more similar objects, where each of these objects has similar functionality. (This is also known as a “has-a” relationship among objects.) The usage of this pattern is common in tree-structured data, and when you implement this pattern in such a data structure, you do not need to discriminate between a branch and the leaf nodes of the tree. As a result, you can achieve these two key goals using this pattern.
  • You can compose objects into a tree structure to represent a partwhole hierarchy.

  • You can access both the composite objects (branches) and the individual objects (leaf nodes) uniformly. As a result, you can reduce the complexity of the code and make the application less prone to errors.

Real-World Example

Apart from our previous example, you can also think of an organization that consists of many departments. In general, an organization has many employees. Some of these employees are grouped to form a department, and those departments can be further grouped to build the high-level structure of the organization.

Computer-World Example

I mentioned that a tree data structure could follow this concept where the clients can treat the leaves of the tree and the nonleaves (or branches of the tree) in the same way. So, when you see a hierarchical data, you can get a clue that the Composite pattern can be useful. XML files are very common examples with such tree structures.

Note

When you traverse the tree, you often use the concept of an Iterator design pattern, which is covered in Chapter 18.

Implementation

In this example, I represent a college organization. Let’s assume there is a principal and two heads of departments (HODs), one for Computer Science and Engineering (CSE), and one for Mathematics (Math). Suppose that in the Mathematics department, there are currently two lecturers (or teachers), and in the Computer Science and Engineering department, there are three lecturers (teachers). The tree structure for this organization looks like Figure 11-1.
../images/463942_2_En_11_Chapter/463942_2_En_11_Fig1_HTML.jpg
Figure 11-1

A college organization with a principal, 2 HODs and 5 lecturers/ teachers

Let’s also assume that at the end of the year, one lecturer from the CSE department submits his resignation. The following example considers all the scenarios mentioned.

Class Diagram

Figure 11-2 shows the class diagram.
../images/463942_2_En_11_Chapter/463942_2_En_11_Fig2_HTML.jpg
Figure 11-2

Class diagram

Solution Explorer View

Figure 11-3 shows the high-level structure of the program.
../images/463942_2_En_11_Chapter/463942_2_En_11_Fig3_HTML.jpg
Figure 11-3

Solution Explorer view

Demonstration

This demonstration features a tree structure. IEmployee is an interface with three read-write properties and one method called DisplayDetails() . It looks like the following.
interface IEmployee
    {
        // To set an employee name
        string Name { get; set; }
        // To set an employee department
        string Dept { get; set; }
        // To set an employee designation
        string Designation { get; set; }
        // To display an employee details
        void DisplayDetails();
    }

From the associated comments, it’s easy to understand that these three properties set an employee’s name, their corresponding department, and the designation. The Employee and CompositeEmployee concrete classes implement this interface. Employee class (lecturers) acts as a leaf node, and the other one is a nonleaf node. One or more employees can report to a HOD. So, it is treated as a nonleaf (or branch) node. Similarly, all HODs report to the principal. So, Principal is another nonleaf node.

The mathematics lecturers are named M. Joy and M. Roony. The CSE teachers are named C. Sam, C. Jones, and C. Marium. These lecturers do not supervise anyone, so they are treated as leaf nodes.

The CompositeEmployee class maintains a list and two additional methods called AddEmployee(...) and RemoveEmployee(...). These methods add an employee to the list or remove an employee from the list.

Now go through the complete implementation, and refer to the supportive comments.
using System;
/* For List<Employee> using
 * the following namespace.
 */
using System.Collections.Generic;
namespace CompositePattern
{
    interface IEmployee
    {
        // To set an employee name
        string Name { get; set; }
        // To set an employee department
        string Dept { get; set; }
        // To set an employee designation
        string Designation { get; set; }
        // To display an employee details
        void DisplayDetails();
    }
    // Leaf node
    class Employee : IEmployee
    {
        public string Name { get; set; }
        public string Dept { get; set; }
        public string Designation { get; set; }
        // Details of a leaf node
        public void DisplayDetails()
        {
            Console.WriteLine($" {Name} works in { Dept} department.Designation:{Designation}");
        }
    }
    // Non-leaf node
    class CompositeEmployee : IEmployee
    {
        public string Name { get; set; }
        public string Dept { get; set; }
        public string Designation { get; set; }
        // The container for child objects
        private List<IEmployee> subordinateList = new List<IEmployee>();
        // To add an employee
        public void AddEmployee(IEmployee e)
        {
            subordinateList.Add(e);
        }
        // To remove an employee
        public void RemoveEmployee(IEmployee e)
        {
            subordinateList.Remove(e);
        }
        // Details of a composite node
        public void DisplayDetails()
        {
            Console.WriteLine($" {Name} works in {Dept} department.Designation:{Designation}");
            foreach (IEmployee e in subordinateList)
            {
                e.DisplayDetails();
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("***Composite Pattern Demo. ***");
            #region Mathematics department
            // 2 lecturers work in Mathematics department
            Employee mathTeacher1 = new Employee { Name = "M.Joy", Dept = "Mathematic", Designation = "Lecturer" };
            Employee mathTeacher2 = new Employee { Name = "M.Roony", Dept = "Mathematics", Designation = "Lecturer" };
            // The college has a Head of Department in Mathematics
            CompositeEmployee hodMaths = new CompositeEmployee { Name = "Mrs.S.Das", Dept = "Maths", Designation = "HOD-Maths" };
            // Lecturers of Mathematics directly reports to HOD-Maths
            hodMaths.AddEmployee(mathTeacher1);
            hodMaths.AddEmployee(mathTeacher2);
            #endregion
            #region Computer Science department
            // 3 lecturers work in Computer Sc. department
            Employee cseTeacher1 = new Employee { Name = "C.Sam", Dept = "Computer Science", Designation = "Lecturer" };
            Employee cseTeacher2 = new Employee { Name = "C.Jones", Dept = "Computer Science.", Designation = "Lecturer" };
            Employee cseTeacher3 = new Employee { Name = "C.Marium", Dept = "Computer Science", Designation = "Lecturer" };
            // The college has a Head of Department in Computer science
            CompositeEmployee hodCompSc = new CompositeEmployee { Name = "Mr. V.Sarcar", Dept = "Computer Sc.", Designation = "HOD-Computer Sc." };
            /* Lecturers of Computer Sc. directly reports to HOD-CSE */
            hodCompSc.AddEmployee(cseTeacher1);
            hodCompSc.AddEmployee(cseTeacher2);
            hodCompSc.AddEmployee(cseTeacher3);
            #endregion
            #region Top level management
            // The college also has a Principal
            CompositeEmployee principal = new CompositeEmployee { Name = "Dr.S.Som", Dept = "Planning-Supervising-Managing", Designation = "Principal" };
            /* Head of Departments's of Maths and Computer Science directly reports to Principal.*/
            principal.AddEmployee(hodMaths);
            principal.AddEmployee(hodCompSc);
            #endregion
            /*
             * Printing the leaf-nodes and branches in the same way. i.e. in each case, we are calling DisplayDetails() method.
             */
            Console.WriteLine(" Details of a Principal object is as follows:");
            // Prints the complete structure
            principal.DisplayDetails();
            Console.WriteLine(" Details of a HOD object is as follows:");
            /* Prints the details of Computer Science department */
            hodCompSc.DisplayDetails();
            // Leaf node
            Console.WriteLine(" Details of an individual employee(leaf node) is as follows:");
            mathTeacher1.DisplayDetails();
            /*
             * Suppose, one Computer Science lecturer(C.Jones)
             * is leaving now from the organization.
             */
            hodCompSc.RemoveEmployee(cseTeacher2);
            Console.WriteLine(" After the resignation of C.Jones, the organization has the following members:");
            principal.DisplayDetails();
            // Wait for user
            Console.ReadKey();
        }
    }
}

Output

Here’s the output.
***Composite Pattern Demo. ***
Details of a Principal object is as follows:
Dr. S.Som works in Planning-Supervising-Managing department.Designation:Principal
Mrs. S.Das works in Maths department.Designation:HOD-Maths
        M.Joy works in Mathematic department.Designation:Lecturer
        M.Roony works in Mathematics department.Designation:Lecturer
Mr. V.Sarcar works in Computer Sc. department.Designation:HOD-Computer Sc.
        C.Sam works in Computer Science department.Designation:Lecturer
        C.Jones works in Computer Science. department.Designation:Lecturer
        C.Marium works in Computer Science department.Designation:Lecturer
Details of a HOD object is as follows:
Mr. V.Sarcar works in Computer Sc. department.Designation:HOD-Computer Sc.
        C.Sam works in Computer Science department.Designation:Lecturer
        C.Jones works in Computer Science. department.Designation:Lecturer
        C.Marium works in Computer Science department.Designation:Lecturer
Details of an individual employee(leaf node) is as follows:
        M.Joy works in Mathematic department.Designation:Lecturer
After the resignation of C.Jones, the organization has the following members:
Dr. S.Som works in Planning-Supervising-Managing department.Designation:Principal
Mrs. S.Das works in Maths department.Designation:HOD-Maths
        M.Joy works in Mathematic department.Designation:Lecturer
        M.Roony works in Mathematics department.Designation:Lecturer
Mr. V.Sarcar works in Computer Sc. department.Designation:HOD-Computer Sc.
        C.Sam works in Computer Science department.Designation:Lecturer
        C.Marium works in Computer Science department.Designation:Lecturer

Q&A Session

11.1 What are the advantages of using the Composite design pattern?

Here are some of the advantages.
  • In a tree-like structure, you can treat both the composite objects (branch nodes) and the individual objects (leaf nodes) uniformly. In this example, I used a common method called DisplayDetails to print both the composite object structure (the principal or department heads) and the single objects (the lecturers).

  • It is common to implement a part-whole hierarchy using this design pattern.

  • You can easily add a new component to the architecture or delete an existing component from the architecture.

11.2 What are the challenges associated with using the Composite design pattern?

Here are some of the disadvantages.
  • If you want to maintain the ordering of child nodes (for example, if the parse trees are represented as components), you may need to take special care.

  • If you are dealing with immutable objects, you cannot delete them.

  • You can easily add a new component, but maintenance can be difficult over a period of time. Sometimes you may want to deal with a composite that has special components. This kind of constraint may cause additional costs to the development because you may need to implement a dynamic checking mechanism to support the concept.

11.3 In this example, you used a list data structure . Are other data structures OK to use?

Absolutely. There is no universal rule. You are free to use your preferred data structure. The GoF also confirmed that it is not necessary to use a general-purpose data structure.

11.4 How do you connect the Iterator design pattern to a Composite design pattern?

In the example, if you want to examine a composite object architecture, you may need to iterate over the objects. Also, if you want to do some special activities with some branches, you may need to iterate over its leaf nodes and non-leaf nodes.

11.5 In your implementation, in the interface, you defined only one method, DisplayDetails. But you are using additional methods for the addition and removal of objects in the composite class (CompositeEmployee). Why are you not putting these methods in the interface?

Nice observation. Even the GoF discussed this. Let’s see what happens if you put the AddEmployee(...) and RemoveEmployee(...) methods in the interface. In that case, the leaf nodes need to implement these addition and removal operations. But will it be meaningful in this case? The answer is no. In this case, it may appear that you lose transparency, but I believe that you have more safety because I blocked the meaningless operations in the leaf nodes. This is why the GoF mentioned that this kind of decision involves a trade-off between safety and transparency.

11.6 I want to use an abstract class instead of an interface. Is this allowed?

In most cases, the simple answer is yes, but you need to understand the difference between an abstract class and an interface. In a typical scenario, you may find that one of them is more useful than the other. Throughout the book, I present only simple and easy-to-understand examples, so you may not see much difference between them.

Note

In the “Q&A Session” section in Chapter 3, which covered the Builder pattern, I discussed how to decide between an abstract class and an interface.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.22.51.241