Composite pattern

From Wikipedia, the free encyclopedia

Jump to: navigation, search

In computer science, the composite pattern is a partitioning design pattern. Composite allows a group of objects to be treated in the same way as a single instance of an object. The intent of composite is to "compose" objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions uniformly.[1]

Contents

[edit] 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. In object-oriented programming, a composite is an object (e.g., a shape) designed as a composition of one-or-more similar objects (other kinds of shapes/geometries), all exhibiting similar functionality. This is known as a "has-a" relationship between objects. The key concept is that you can manipulate a single instance of the object just as you would manipulate a group of them. The operations you can perform on all the composite objects often have a least common denominator relationship. For example, if defining a system to portray grouped shapes on a screen, it would be useful to define resizing a group of shapes to have the same effect (in some sense) as resizing a single shape.

[edit] When to use

Composite can be used when clients should ignore the difference between compositions of objects and individual objects.[1] 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.

[edit] Structure

Composite pattern in UML.
Composite pattern in LePUS3.

[edit] Component

  • is the abstraction for all components, including composite ones
  • 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

[edit] Leaf

  • represents leaf objects in the composition
  • implements all Component methods

[edit] Composite

  • represents a composite Component (component having children)
  • implements methods to manipulate children
  • implements all Component methods, generally by delegating them to its children

[edit] Example

[edit] Common Lisp

The following example, written in Common Lisp, and translated directly from the Java example below it, implements a method named print-graphic, which can be used on either an ellipse, or a list whose elements are either lists or ellipses.

(defstruct ellipse) ;; An empty struct.
 
;; For the method definitions, "object" is the variable,
;; and the following word is the type.
 
(defmethod print-graphic ((object null))
  NIL)
 
(defmethod print-graphic ((object cons))
  (print-graphic (first object))
  (print-graphic (rest object)))
 
(defmethod print-graphic ((object ellipse))
  (print 'ELLIPSE))
 
(let* ((ellipse-1 (make-ellipse))
       (ellipse-2 (make-ellipse))
       (ellipse-3 (make-ellipse))
       (ellipse-4 (make-ellipse)))
 
  (print-graphic (cons (list ellipse-1 (list ellipse-2 ellipse-3)) ellipse-4)))

[edit] Java

The following example, written in Java, implements a graphic class, which can be either an ellipse or a composition of several graphics. Every graphic can be printed. In algebraic form,

       Graphic = ellipse | GraphicList
       GraphicList = empty | Graphic GraphicList

It could be extended to implement several other shapes (rectangle, etc.) and methods (translate, etc.).

import java.util.List;
import java.util.ArrayList;
 
/** "Component" */
interface Graphic {
 
    //Prints the graphic.
    public void print();
 
}
 
/** "Composite" */
class CompositeGraphic implements Graphic {
 
    //Collection of child graphics.
    private List<Graphic> mChildGraphics = new ArrayList<Graphic>();
 
    //Prints the graphic.
    public void print() {
        for (Graphic graphic : mChildGraphics) {
            graphic.print();
        }
    }
 
    //Adds the graphic to the composition.
    public void add(Graphic graphic) {
        mChildGraphics.add(graphic);
    }
 
    //Removes the graphic from the composition.
    public void remove(Graphic graphic) {
        mChildGraphics.remove(graphic);
    }
 
}
 
/** "Leaf" */
class Ellipse implements Graphic {
 
    //Prints the graphic.
    public void print() {
        System.out.println("Ellipse");
    }
 
}
 
/** Client */
public class Program {
 
    public static void main(String[] args) {
        //Initialize four ellipses
        Ellipse ellipse1 = new Ellipse();
        Ellipse ellipse2 = new Ellipse();
        Ellipse ellipse3 = new Ellipse();
        Ellipse ellipse4 = new Ellipse();
 
        //Initialize three composite graphics
        CompositeGraphic graphic = new CompositeGraphic();
        CompositeGraphic graphic1 = new CompositeGraphic();
        CompositeGraphic graphic2 = new CompositeGraphic();
 
        //Composes the graphics
        graphic1.add(ellipse1);
        graphic1.add(ellipse2);
        graphic1.add(ellipse3);
 
        graphic2.add(ellipse4);
 
        graphic.add(graphic1);
        graphic.add(graphic2);
 
        //Prints the complete graphic (four times the string "Ellipse").
        graphic.print();
    }
}

[edit] Python

class Component(object):
    def __init__(self, *args, **kw):
        pass
 
class Leaf(Component):
    def __init__(self, *args, **kw):
        Component.__init__(self, *args, **kw)
 
class Composite(Component):
    def __init__(self, *args, **kw):
        Component.__init__(self, *args, **kw)
        self.children = []
 
    def append_child(self, child):
        self.children.append(child)
 
    def remove_child(self, child):
        self.children.remove(child)
 
c = Composite()
l = Leaf()
c.append_child(l)

[edit] See also

[edit] External links

[edit] References

  1. ^ a b Gamma, Erich; Richard Helm, Ralph Johnson, John M. Vlissides (1995). Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley. pp. 395. ISBN 0201633612. 

Parts of this article originated from the Perl Design Patterns Book