Composite pattern
From Wikipedia, the free encyclopedia
In computer science, the composite pattern is a design pattern: "A general solution to a common problem in software design."
Motivation: 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, when resizing a single shape to fill the screen, surely you would expect/desire that resizing a group of shapes would have the same effect.
When to use: You find that you are using multiple objects in the same way, and often have nearly identical code to handle each of them -- the only differences being that you are manipulating an instance of a 'circle' versus a 'square', for instance. Useful if differentiation doesn't need to exist, and it would be easier to think of them as homogeneous. (Of course, you could still provide functionality to manipulate only a single instance -- like selecting an item from a list instead of operating on the whole list.)
Compose means a special thing: it refers to building objects using DelegationConcept. Delegation-composition hangs onto constituent parts-using references. By contrast, mixins inherit from each part. MixIns prevent returning a WholeObject in response to requests for information, and they prevent having more than one of any given part.
The composite pattern is an object oriented pendant to algebraic data types.
Contents |
[edit] Structure
- Component
-
- declares the interface for object composition
- implements default behaviour
- declares an interface for accessing and managing the child components
- Leaf (Feuille)
- represents leaf objects in the composition
- Composite
-
- defines behaviour for components having children
- stores child components
- implements child-related operations to the Component interface
- Client
- manipulates objects in the composition through the Component interface
[edit] Examples
[edit] C#
The following C# program illustrates the 'Europe' example given above and will output:
(Europe: (England: London) (France: Paris))
using System; using System.Text; namespace CompositePattern { class Program { public static void Main(string[] args) { Composite england = new Composite("England"); Leaf york = new Leaf("York"); Leaf london = new Leaf("London"); england.AddComponent(york); england.AddComponent(london); england.RemoveComponent(york); Composite france = new Composite("France"); france.AddComponent(new Leaf("Paris")); Composite europe = new Composite("Europe"); europe.AddComponent(england); europe.AddComponent(france); Console.WriteLine(europe.DefaultMethod()); Console.ReadLine(); } } public interface IComponent { string DefaultMethod(); IComponentCollection GetChildren(); bool AddComponent(IComponent c); bool RemoveComponent(IComponent c); } // The Java example uses Generics, but these are not available in .Net 1.1 public class IComponentCollection : System.Collections.CollectionBase { public bool Add(IComponent o) { return (base.InnerList.Add(o) >= 0); } public bool Remove(IComponent o) { try { base.InnerList.Remove(o); return true; } catch { return false; } } public IComponent this[int index] { get { return (IComponent)base.InnerList[index]; } set { base.InnerList[index] = value; } } } public class Composite : IComponent { private string _ID; private IComponentCollection _Components = new IComponentCollection(); public Composite(string identification) { _ID = identification; } public string DefaultMethod() { System.Text.StringBuilder sbOutput = new System.Text.StringBuilder(); sbOutput.Append(string.Format("({0}:", _ID)); foreach (IComponent child in GetChildren()) { sbOutput.Append(" " + child.DefaultMethod()); } sbOutput.Append(")"); return sbOutput.ToString(); } public IComponentCollection GetChildren() { return _Components; } public bool AddComponent(IComponent c) { return _Components.Add(c); } public bool RemoveComponent(IComponent c) { return _Components.Remove(c); } } public class Leaf : IComponent { private string _ID; public Leaf(string identification) { _ID = identification; } public string DefaultMethod() { return _ID; } public IComponentCollection GetChildren() { return null; } public bool AddComponent(IComponent c) { return false; } public bool RemoveComponent(IComponent c) { return false; } } }
[edit] JAVA
The following JAVA program illustrates the previous.NET example again.
// The "DefaultMethod()" was renamed to be "toString()" in this version. // requires JDK 1.5 or above, for generics List<E> and foreach loop // To compile and execute this code: // javac -cp . Main.java // java -cp . Main import java.util.List; import java.util.ArrayList; import java.util.Collection; public class Main { public static void main(String[] args) { Composite england = new Composite("England"); Leaf york = new Leaf("York"); Leaf london = new Leaf("London"); england.addComponent(york); england.addComponent(london); england.removeComponent(york); Composite france = new Composite("France"); france.addComponent(new Leaf("Paris")); Composite europe = new Composite("Europe"); europe.addComponent(england); europe.addComponent(france); System.out.println(europe.toString()); } } interface IComponent { Collection getChildren(); boolean addComponent(IComponent c); // add composite or leaf boolean removeComponent(IComponent c); } class Composite implements IComponent { private String id; private List<IComponent> list = new ArrayList<IComponent> (); public Composite(String id) { this.id = id; } public String toString() { StringBuilder buf = new StringBuilder(); buf.append(String.format("(%s:", id)); // JDK 1.5 "foreach" implicitly uses an iterator to walk over list for (IComponent child : list) { buf.append(" " + child.toString()); } buf.append(")"); return buf.toString(); } //public List<IComponent> getChildren() public Collection getChildren() { return list; } public boolean addComponent(IComponent c) { return list.add(c); } public boolean removeComponent(IComponent c) { return list.remove(c); } } class Leaf implements IComponent { private String id; public Leaf(String id) { this.id = id; } public String toString() { return this.id; } public Collection getChildren() { return null; } // false because failed to add public boolean addComponent(IComponent c) { return false; } // false because failed to find it for removal public boolean removeComponent(IComponent c) { return false; } }
[edit] See also
- Design Patterns: The book that started it all.
- Mixin
- Facade pattern
- Decorator pattern
- Law of Demeter
- Delegation pattern
- Builder pattern
- Abstract factory pattern
[edit] External links
- Description from the Portland Pattern Repository
- Class::Delegation on CPAN
- Chinese Ring Puzzle Applet
- "The End of Inheritance: Automatic Run-time Interface Building for Aggregated Objects" by Paul Baranowski
- Composite Pattern by Vince Huston
- A persistent implementation of the Composite Pattern using Hibernate
- Note the above isn't a representation of the Composite Pattern
Parts of this article originated from the Perl Design Patterns Book
Creational: Abstract factory • Builder • Factory • Prototype • Singleton
Structural: Adapter • Bridge • Composite • Decorator • Façade • Flyweight • Proxy
Behavorial: Chain of responsibility • Command • Interpreter • Iterator • Mediator • Memento • Observer • State • Strategy • Template method • Visitor