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 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 | ellipse GraphicList

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

List = empty_list | atom List | List List

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 Example

# Component
class Graphic:
	# Prints the graphic
	def printGraphic(self):
		pass
 
# Composite
class CompositeGraphic(Graphic):
 
	def __init__(self):
		# Collection of child graphics
		self.__mChildGraphics = []
 
	# Prints the graphic.
	def printGraphic(self):
		for graphic in self.__mChildGraphics:
			graphic.printGraphic()
 
	# Adds the graphic to the composition.
	def add(self, graphic):
		self.__mChildGraphics.append(graphic)
 
	# Removes the graphic from the composition.
	def remove(self, graphic):
		self.__mChildGraphics.remove(graphic)
 
# Leaf
class Ellipse(Graphic):
 
	def printGraphic(self):
		print "Ellipse"
 
def main():
	# Initialize four ellipses
	ellipse1 = Ellipse()
	ellipse2 = Ellipse()
	ellipse3 = Ellipse()
	ellipse4 = Ellipse()
 
	# Initialize three composite graphics
	graphic = CompositeGraphic()
	graphic1 = CompositeGraphic()
	graphic2 = 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.printGraphic()
 
if __name__ == "__main__":
	main()

[edit] C++ Example

#include <vector>
#include <iostream> // std::cout
#include <memory> // std::auto_ptr
#include <algorithm> // std::for_each
#include <functional> // std::mem_fun
using namespace std;
 
class Graphic
{
public:
  virtual void print() const = 0;
  virtual ~Graphic() {}
};
 
class Ellipse : public Graphic
{
public:
  void print() const {
    cout << "Ellipse \n";
  }
};
 
class CompositeGraphic : public Graphic
{
public:
  void print() const {
    // for each element in graphicList_, call the print member function
    for_each(graphicList_.begin(), graphicList_.end(), mem_fun(&Graphic::print));
  }
 
  void add(Graphic *aGraphic) {
    graphicList_.push_back(aGraphic);
  }
 
private:
  vector<Graphic*>  graphicList_;
};
 
int main()
{
  // Initialize four ellipses
  const auto_ptr<Ellipse> ellipse1(new Ellipse());
  const auto_ptr<Ellipse> ellipse2(new Ellipse());
  const auto_ptr<Ellipse> ellipse3(new Ellipse());
  const auto_ptr<Ellipse> ellipse4(new Ellipse());
 
  // Initialize three composite graphics
  const auto_ptr<CompositeGraphic> graphic(new CompositeGraphic());
  const auto_ptr<CompositeGraphic> graphic1(new CompositeGraphic());
  const auto_ptr<CompositeGraphic> graphic2(new CompositeGraphic());
 
  // Composes the graphics
  graphic1->add(ellipse1.get());
  graphic1->add(ellipse2.get());
  graphic1->add(ellipse3.get());
 
  graphic2->add(ellipse4.get());
 
  graphic->add(graphic1.get());
  graphic->add(graphic2.get());
 
  // Prints the complete graphic (four times the string "Ellipse")
  graphic->print();
  return 0;
}

[edit] C# Example

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace Composite
{
    /// <summary>
    /// Component
    /// </summary>
    public interface IGraphic
    {
        void print();
    }
    /// <summary>
    /// Composite
    /// </summary>
    public class CompositeGraphic:IGraphic
    {
        private List<IGraphic> m_ChildGraphics = new List<IGraphic>();
        #region Graphic Members
 
        public void print()
        {
            foreach (IGraphic graphic in m_ChildGraphics)
                graphic.print();
        }
        //Adds the graphic to the composition.
        public void add(IGraphic graphic)
        {
            m_ChildGraphics.Add(graphic);
        }
 
        //Removes the graphic from the composition.
        public void remove(IGraphic graphic)
        {
            m_ChildGraphics.Remove(graphic);
        }
        #endregion
    }
    /// <summary>
    /// Leaf
    /// </summary>
    public class Ellipse : IGraphic
    {
        #region IGraphic Members
 
        public void print()
        {
            Console.WriteLine("Ellipse");
        }
 
        #endregion
    }
 
    class Program
    {
        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();
            Console.ReadLine();
        }
    }
}


[edit] Smalltalk Example

"Creates the Ellipse class, subclass of Object"
Object subclass: #Ellipse.
 
"Defines the method print on an Ellipse which prints the word 'Ellipse' and a new line"
Ellipse>>print
  Transcript
    show: 'Ellipse';
    cr.
 
"Creates the CompositeGraphic class, subclass of Object, having one instance variable"
Object
  subclass: #CompositeGraphic 
  instanceVariableNames: 'childGraphics'.
 
CompositeGraphic>>initialize
  super initialize.
  childGraphics := OrderedCollection new.
 
CompositeGraphic>>add: child
  childGraphics add: child.
 
CompositeGraphic>>print
  childGraphics do: [:each | each print].
 
 
"Main part which creates some ellipses and composites"
|graphic1 graphic2 graphic ellipse1 ellipse2 ellipse3 ellipse4|
ellipse1 := Ellipse new.
ellipse2 := Ellipse new.
ellipse3 := Ellipse new.
ellipse4 := Ellipse new.
 
graphic1 := CompositeGraphic new
                add: ellipse1;
                add: ellipse2;
                add: ellipse3;
                yourself.
 
graphic2 := CompositeGraphic new
                add: ellipse4;
                yourself.
 
graphic := CompositeGraphic new
                add: graphic1;
                add: graphic2;
                yourself.
 
graphic print.

[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

Personal tools