Composite - Design Pattern

Composite - Design Pattern

Software Architecture Simplified

ยท

3 min read

Objective ๐ŸŽฏ

Provide a way to compose objects into tree structures, also known as part-whole hierarchy, allowing the client to treat/work with each object of the structure individually.

Notes ๐Ÿ“

โ€ข Composite pattern makes sense just in scenarios where the model can be represented as a tree.

Type โœ…

โŒBehavioral: Describes how objects interact/communicate between themselves.

โŒCreational: Describes how to instantiate an object without large and complex.

โœ”๏ธStructural: Describes how objects/classes are composed to form larger structures.

UML ๐Ÿ“

image.png

Participants ๐Ÿ”—

โ€ข Component:

  • Declares the interface for objects in the composition with the default behaviour common to all classes

โ€ข Leaf:

  • Implements Component interface
  • Represents leaf objects (components with no children)

โ€ข Composite:

  • Implements Component interface
  • Declares an interface for accessing and managing its child components
  • Store children components

Sample Code ๐ŸŽฎ

Structural Example ๐Ÿ›๏ธ

image.png

public static class CompositeStructural
    {
        public static void Execute()
        {
            Composite lRoot = new Composite("Root");
            lRoot.Add(new Leaf("Leaf A"));
            lRoot.Add(new Leaf("Leaf B"));

            Composite lComposite = new Composite("Composite X");
            lComposite.Add(new Leaf("Leaf XA"));
            lComposite.Add(new Leaf("Leaf XB"));

            lRoot.Add(lComposite);
            lRoot.Add(new Leaf("Leaf C"));

            Leaf lLeaf = new Leaf("Leaf D");
            lRoot.Add(lLeaf);
            lRoot.Remove(lLeaf);

            // Recursively display tree
            lRoot.Display(1);
        }
    }

    public abstract class Component
    {
        protected string _Name;

        public Component(string prName)
        {
            _Name = prName;
        }

        public abstract void Display(int prDepth);
    }

    public class Composite : Component
    {
        private List<Component> _Children = new List<Component>();

        public Composite(string prName)
            : base(prName)
        {
        }

        public void Add(Component prComponent)
        {
            _Children.Add(prComponent);
        }

        public void Remove(Component prComponent)
        {
            _Children.Remove(prComponent);
        }

        public override void Display(int prDepth)
        {
            Console.WriteLine(new String('-', prDepth) + _Name);

            // Recursively display child nodes
            foreach (Component lComponentCurrent in _Children)
            {
                lComponentCurrent.Display(prDepth + 2);
            }
        }
    }

    public class Leaf : Component
    {
        // Constructor
        public Leaf(string prName)
            : base(prName)
        {
        }

        public override void Display(int prDepth)
        {
            Console.WriteLine(new String('-', prDepth) + _Name);
        }
    }

Output

image.png

Real-world Example ๐Ÿ”ฅ

image.png

public static class CompositePractical
    {
        public static void Execute()
        {
            ManagementMember lDirector = new ManagementMember("Director");

            ManagementMember lManagerDeptA = new ManagementMember("Manager Department A");
            lManagerDeptA.Add(new StaffMember("Staff 1 Department A"));
            lManagerDeptA.Add(new StaffMember("Staff 2 Department A"));
            ManagementMember lSupervisorDeptA = new ManagementMember("Supervisor Department A");
            lSupervisorDeptA.Add(new StaffMember("Staff 3 Department A"));
            lSupervisorDeptA.Add(new StaffMember("Staff 4 Department A"));
            lManagerDeptA.Add(lSupervisorDeptA);

            ManagementMember lManagerDeptB = new ManagementMember("Manager Department B");
            lManagerDeptB.Add(new StaffMember("Staff 1 Department B"));
            lManagerDeptB.Add(new StaffMember("Staff 2 Department B"));
            lManagerDeptB.Add(new StaffMember("Staff 3 Department B"));
            lManagerDeptB.Add(new StaffMember("Staff 4 Department B"));

            lDirector.Add(lManagerDeptA);
            lDirector.Add(lManagerDeptB);

            lDirector.Display(1);
        }                                                         
    }

    public abstract class Employee
    {
        protected string _Name;

        public Employee(string prName)
        {
            _Name = prName;
        }

        public abstract void Display(int prDepth);
    }

    public class ManagementMember : Employee
    {
        private List<Employee> _Employees = new List<Employee>();

        public ManagementMember(string prName)
            : base(prName)
        {
        }

        public void Add(Employee prEmployee)
        {
            _Employees.Add(prEmployee);
        }

        public void Remove(Employee prEmployee)
        {
            _Employees.Remove(prEmployee);
        }

        public override void Display(int prDepth)
        {
            Console.WriteLine(new String('-', prDepth) + _Name);

            // Recursively display child nodes
            foreach (Employee lEmployeeCurrent in _Employees)
            {
                lEmployeeCurrent.Display(prDepth + 2);
            }
        }
    }

    public class StaffMember : Employee
    {
        // Constructor
        public StaffMember(string prName)
            : base(prName)
        {
        }

        public override void Display(int prDepth)
        {
            Console.WriteLine(new String('-', prDepth) + _Name);
        }
    }

Output

image.png

Source Code ๐ŸŽฒ

github.com/VictorLins/DesignPatterns

Did you find this article valuable?

Support Victor Lins by becoming a sponsor. Any amount is appreciated!

ย