Wednesday, November 17, 2010

Composite Design Pattern - Structural

1.1     Definition

-      Composite allows a group of objects to be treated in the same way as a single instance of an object.
-      Compose objects into tree structures to represent part-whole hierarchies.
-      Composite lets clients treat individual objects and compositions of objects uniformly. This is called Recursive Composition.  

1.2     Intent

  • When each item in the collection might itself contain collections of other objects, the use of the Composite pattern is appropriate.
  • Composite is an easy way to represent tree-like collections without having to treat parent and leaf nodes differently.

1.3     Motivation

  • When dealing with tree-structured data, programmers often have to discriminate between a leaf-node and a branch. This makes code more complex, and therefore, error prone. The solution is an interface that allows treating complex and primitive objects uniformly.

1.4     Applicability

  • You want to represent part-whole hierarchies of objects.
  • You want clients to be able to ignore the difference between compositions of objects and individual objects.
  • If programmers find that they are using multiple objects in the same way, and often have nearly identical code to handle each of them, then composite is a good choice; it is less complex in this situation to treat primitives and composites as homogeneous.

1.5     Structure


 

1.6     Participants

The classes and/or objects participating in this pattern are:

  • Component
    • declares the interface for objects in the composition.
    • implements default behavior for the interface common to all classes, as appropriate.
    • declares an interface for accessing and managing its child components.
    • (optional) defines an interface for accessing a component's parent in the recursive structure, and implements it if that's appropriate.

  • Leaf
    • represents leaf objects in the composition. A leaf has no children.
    • defines behavior for primitive objects in the composition.

  • Composite
    • defines behavior for components having children.
    • stores child components.
    • implements child-related operations in the Component interface.



  • Cleint
    • manipulates objects in the composition through the Component interface.

1.7     Sample Code

This structural code demonstrates the Proxy pattern which provides a representative object (proxy) that controls access to another similar object.


  abstract class Component
  {
    protected string name;

    // Constructor
    public Component(string name)
    {
      this.name = name;
    }

    public abstract void Add(Component c);
    public abstract void Remove(Component c);
    public abstract void Display(int depth);
  }

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

    public override void Add(Component c)
    {
      Console.WriteLine("Cannot add to a leaf");
    }

    public override void Remove(Component c)
    {
      Console.WriteLine("Cannot removef");
    }

    public override void
Display(int depth)
    {
      Console.WriteLine(new String('-', depth) + name);
    }
  }
class Composite : Component
  {
    private ArrayList children = new ArrayList();

    // Constructor
    public Composite(string name) : base(name)
    { 
    }

    public override void Add(Component component)
    {
      children.Add(component);
    }

    public override void Remove(Component component)
    {
      children.Remove(component);
    }

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

      foreach (Component component in children)
      {
        component.Display(depth + 2);
      }
    }
  }

class MainApp
  {
    static void Main()
    static void Main()
    {
      // Create a tree structure
      Composite root = new Composite("root");
      root.Add(new Leaf("Leaf A"));
      root.Add(new Leaf("Leaf B"));

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

      root.Add(comp);
      root.Add(new Leaf("Leaf C"));

      // Add and remove a leaf
      Leaf leaf = new Leaf("Leaf D");
      root.Add(leaf);
      root.Remove(leaf);

      // Recursively display tree
      root.Display(1);

      // Wait for user
      Console.Read();
    } 
}

Output –

-root
---Leaf A
---Leaf B
---Composite X
-----Leaf XA
-----Leaf XB
---Leaf C

1.8     More Realistic - Sample Code




-       The Composite class is a concrete component like Leaf1 and Leaf2, but has no operation() behavior of its own.   
-       Instead, Composite is composed with a collection of other abstract components, which may be of any other concrete component type including the composite itself.  
-       The unifying fact is that they are all abstractly AComponents.  
-       When the operation() method of a Composite object is called, it simply dispatches the request sequentially to all of its "children" components. 

For instance, a Composite object could hold references to both a Leaf1 and a Leaf2 instance.   If a client holds a reference to that Composite object and calls its operation() method, the Composite object will first call operation on its Leaf1 instance and then operation() on its Leaf2 instance.   Thus composite behavior of Leaf1 plus Leaf2 behaviors is achieved without either duplicating code or by having the Client object knowing that the two leaf components were involved. 

1.9     Composite in .Net

When dealing with collections of objects, there are often operations that are appropriate for both a single object and the entire collection. Think about an ASP.NET control. A control may be a simple single item like a Literal, or it could be composed of a complex collection of child controls, like a DataGrid is. Regardless, calling the Render method on either of these controls should still perform the same intuitive function.

When each item in the collection might itself contain collections of other objects, the use of the Composite pattern is appropriate. Composite is an easy way to represent tree-like collections without having to treat parent and leaf nodes differently.

The canonical example of Composite relies on an abstract base class, Component, that contains both methods for adding and removing children, and the operations common among parents and children.

ASP.NET uses this formulation exactly with System.Web.UI.Control. Control represents the Component base class. It has operations for dealing with children as well as standard operations and properties like Render and Visible. Each object, whether a primitive object (like Literal) or a composite of several objects (like DataGrid), inherits from this base class.


 

 

Regardless of whether a control is a Literal or a DataGrid, the use of Composite means you can just call Render and everything will sort itself out.

Because the domain of controls is so diverse, there are several intermediate derived classes like WebControl and BaseDataList that serve as base classes for other controls. Though these classes expose additional properties and methods, they still retain the child management functions and core operations inherited from Control. In fact, the use of the Composite pattern helps to hide their complexity, if desired.

1.10  Pros/Cons

Benefits
  • It makes it easy to add new kinds of components
  • It makes clients simpler, since they do not have to know if they are dealing with a leaf or a composite component

Liabilities
  • It makes it harder to restrict the type of components of a composite.

1.11  Implementation Issues

Where should the child management methods (add(), remove(), getChild()) be declared?

·         In the Component class: Gives transparency, since all components can be treated the same. But it's not safe, since clients can try to do meaningless things to leaf components at run-time.
·         In the Composite class: Gives safety, since any attempt to perform a child operation on a leaf component will be caught at compile-time. But we lose transparency, since now leaf and composite components have different interfaces.



Should Component maintain the list of components that will be used by a composite object? That is, should this list be an instance variable of Component rather than Composite?
-       Better to keep this part of Composite and avoid wasting the space in every leaf object.

Hope this helps.

Thanks & Regards,
Arun Manglick

No comments:

Post a Comment