Composite Pattern

mike55

Contributor
Joined
Mar 26, 2004
Messages
727
Location
Ireland
Hi all

I have being looking through the book "Design Patterns" by the Gang of Four, I came across the composite pattern and implemented a sample app the demonstrates the pattern working (hopefully I did it correctly).

After some further reading using the web other resources, I came across a statement that said that a child in the pattern could have multiple parents. I have being trying to figure out how to adjust my sample app to accomidate this; I considered adding an list to the child, which allowed it to store a reference to all its parents, and the same for the parent, so that it could store all its children.

I am not sure if this is the best approach, can anyone suggest any alternative?

Here is the code that I am using in my basic composite pattern:
The Abstract child
Code:
using System;
using System.Collections.Generic;
using System.Text;

namespace CompositePattern
{
    abstract class AbstractChild : CompositePattern.IAbstractChild
    {
        protected string name;

        public AbstractChild(string name)
        {
            this.name = name;
        }

        public abstract void Add(AbstractChild soldier);
        public abstract void Remove(AbstractChild soldier);
        public abstract void Display(int indent);
    }
}

The Child
Code:
using System;
using System.Collections.Generic;
using System.Text;

namespace CompositePattern
{
    class Child: AbstractChild
    {
        public Child(string name):base(name)
        {
        }

        public override void Add(AbstractChild soldier)
        {
            Console.WriteLine("Cannot add to a child.");
            //(throw new Exception("The method or operation is not implemented.");
        }

        public override void Remove(AbstractChild soldier)
        {
            Console.WriteLine("Cannot remove from a child.");
            //throw new Exception("The method or operation is not implemented.");
        }

        public override void Display(int indent)
        {
            Console.WriteLine(new string('-', indent) + " " + name);
            //throw new Exception("The method or operation is not implemented.");
        }
    }
}

The parent
Code:
using System;
using System.Collections.Generic;
using System.Text;

namespace CompositePattern
{
    class Parent: AbstractChild
    {
        //private ArrayList elements = new ArrayList();
        private List<AbstractChild> elements = new List<AbstractChild>();

        public Parent(string name): base(name)
        {
        }

        public override void Add(AbstractChild soldier)
        {
            elements.Add(soldier);
            //throw new Exception("The method or operation is not implemented.");
        }

        public override void Remove(AbstractChild soldier)
        {
            elements.Remove(soldier);
            //throw new Exception("The method or operation is not implemented.");
        }

        public override void Display(int indent)
        {
            Console.WriteLine(new string('-', indent) + " + " + name);

            foreach (AbstractChild aSoldier in elements)
            {
                aSoldier.Display(indent + 2);
            }
            //throw new Exception("The method or operation is not implemented.");
        }
    }
}

And finally the main
Code:
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;

namespace CompositePattern
{
    class MainApp
    {
        public static void Main()
        {
            Parent myParent = new Parent("John Doe");

            myParent.Add(new Child("Tom"));
            myParent.Add(new Child("Dick"));
            myParent.Add(new Child("Harry"));

            myParent.Display(0);
            
            Console.Read();
        }

    }
}

Mike55.
 
Is the flyweight pattern the way to go with this problem? I am after reading in http://www.research.ibm.com/designpatterns/pubs/ph-jun98.pdf in the last paragraph on page 4, that the composite pattern can generate a lot of overhead if you are applying it to too fine a granularity.

The flyweight is appliciable if there is a lot of redundancy.

Any suggestions? or am I going completely off track.

Mike55
 
Here is what I have finished up with, I would appreciate it if anyone could let me know if I have done it correctly, or if I have completely mis-read the documentation.

The Component Class.
Code:
using System;
using System.Collections.Generic;
using System.Text;

namespace CompositePattern
{
    abstract class AbstractEmployee : CompositePattern.IAbstractEmployee
    {
        public string name;
        public string title;
        public decimal salary;
        //This is a list of references for all my parents. See GoF pg166(Implementation pt1.) for reasoning.
        public List<AbstractEmployee> myParents = new List<AbstractEmployee>();

        public AbstractEmployee(string name, string title, decimal salary)
        {
            this.name = name;
            this.title = title;
            this.salary = salary;
        }

        //Add a leaf to a parent, or add a parent to another parent.        
        public abstract void Add(AbstractEmployee employee);

        //Remove a leaf from a parent.
        public abstract void Remove(AbstractEmployee employee);

        //Display all the leaves for a particular parent.
        public abstract void Display(int indent);

        //Get the name of the parent/leaf.
        public abstract string GetName();

        //Get the salary of the parent/leaf.
        public abstract string GetTitle();

        //Get the salary of the parent/leaf.
        public abstract decimal GetSalary();
        
        //Add a new reference to the object for a new parent.
        public abstract void AddParentReference(AbstractEmployee myParentRef);

        //List all the references to parents that an object has.
        public abstract void ListParentReference();

        public abstract void RemoveReferences(CompositeElement myParentRef);

    }
}

The Composite Class
Code:
using System;
using System.Collections.Generic;
using System.Text;

namespace CompositePattern
{
    class CompositeElement: AbstractEmployee
    {
        List<AbstractEmployee> myElements = new List<AbstractEmployee>();

        public CompositeElement(string name, string title, decimal salary): base(name, title, salary)
        {
        }

        //Add an employee to the manger.
        public override void Add(AbstractEmployee myEmployee)
        {
            myElements.Add(myEmployee);
        }

        //Remove an employee from the manger.
        public override void Remove(AbstractEmployee myEmployee)
        {
            myElements.Remove(myEmployee);
        }

        //1. Begin by printing the name of the parent, 2. followed by its children.
        public override void Display(int indent)
        {
            //1. Print the name of the parnet.
            Console.WriteLine(new string('-', indent) + "+ " + name);

            //2. Print all the children of the parent.
            foreach (AbstractEmployee myEmployee in myElements)
            {
                myEmployee.Display(indent + 1);
            }
        }

        //Return the name of a parent.
        public override string GetName()
        {
            return name;
        }

        //Return the title of the parent.
        public override string GetTitle()
        {
            return title;
        }

        //Return the salary of the parent.
        public override decimal GetSalary()
        {
            return salary;
        }

        //Add a reference to the parent.
        public override void AddParentReference(AbstractEmployee myParentRef)
        {
            myParents.Add(myParentRef);
        }

        //List all the references that the parent has to other parents.
        public override void ListParentReference()
        {
            if (myParents.Count == 0)
            {
                Console.WriteLine("No references exist.");
            }
            else
            {
                //1. Print the name of the parnet.
                Console.WriteLine(new string('-', 1) + "+ " + name);
                int counter = 0;
                //Print all the references that the object has to parents.
                foreach (AbstractEmployee myRef in myParents)
                {
                    counter += 1;
                    Console.WriteLine("Reference " + counter + ": " + myRef.GetName());
                }
            }
        }

        //Remove a reference to a parent.
        public override void RemoveReferences(CompositeElement myParentRef)
        {
            myParents.Remove(myParentRef);
        }
    }
}

The Leaf Class
Code:
using System;
using System.Collections.Generic;
using System.Text;

namespace CompositePattern
{
    class Employee: AbstractEmployee
    {
        public Employee(string name, string title, decimal salary):base(name, title, salary)
        {
        }

        public override void Add(AbstractEmployee myEmployee)
        {
            Console.WriteLine("Cannot ADD to an employee, operation can only be performed on an manager.");
        }

        public override void Remove(AbstractEmployee myEmployee)
        {
            Console.WriteLine("Cannot REMOVE from an employee, operation can only be performed on an manager.");
        }

        //Display the employee.
        public override void Display(int indent)
        {
            Console.WriteLine(new string('-', indent) + " " + name);
        }

        //Get the name of the employee.
        public override string GetName()
        {
            return name;
        }

        //Get the title of the employee.
        public override string GetTitle()
        {
            return title;
        }

        //Get the salary of the employee.
        public override decimal GetSalary()
        {
            return salary;
        }

        //Add a reference to the child.
        public override void AddParentReference(AbstractEmployee myParentRef)
        {
            //Console.WriteLine("Cannot ADD_PARENT_REFERENCE from an employee, operation can only be performed on an manager.");
            myParents.Add(myParentRef);
        }

        //List all the references that the child has to other parents.
        public override void ListParentReference()
        {
            if (myParents.Count == 0)
            {
                Console.WriteLine("No references exist.");
            }
            else
            {
                //1. Print the name of the parnet.
                Console.WriteLine(new string('-', 1) + "+ " + name);

                int counter = 0;
                //Print all the references that the object has to parents.
                foreach (AbstractEmployee myRef in myParents)
                {
                    counter += 1;
                    Console.WriteLine("Reference " + counter + ": " + myRef.GetName());
                }
            }
        }

        //Remove a reference to a parent.
        public override void RemoveReferences(CompositeElement myParentRef)
        {
            myParents.Remove(myParentRef);
        }
    }
}

And finally, the code from my Main class
Code:
  //1. Create the primary parent.
            CompositeElement root = new CompositeElement("PJimmy", "Managing Director", 100000);
            CompositeElement comp = new CompositeElement("PMichael", "Developer", 17000);

            //2. Create an employee and add a reference.
            Employee emp = new Employee("Tom", "Quality Manager", 50000);
            emp.AddParentReference(root);
            emp.AddParentReference(comp);

            comp.AddParentReference(root);
            
            //Display the references.
            emp.ListParentReference();

Mike55.
 
Back
Top