Composite pattern
From Wikipedia, the free encyclopedia
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
[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
- Design Patterns (book) - the book that started it all
- Mixin
- Facade pattern
- Decorator pattern
- Law of Demeter
- Delegation pattern
- Builder pattern
- Abstract factory pattern
[edit] External links
- Composite pattern description from the Portland Pattern Repository
- Composite pattern in UML and in LePUS3, a formal modelling language
- Class::Delegation on CPAN
- Chinese Ring Puzzle Applet
- "The End of Inheritance: Automatic Run-time Interface Building for Aggregated Objects" by Paul Baranowski
- PerfectJPattern Open Source Project, Provides componentized implementation of the Composite Pattern in Java
[edit] References
- ^ 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.
This article's citation style may be unclear. The references used may be clearer with a different or consistent style of citation, footnoting, or external linking. |
Parts of this article originated from the Perl Design Patterns Book
|