Composite Design Pattern
Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly. (dofactory)
- Component declares the interface for objects in the composition and implements default behavior for the interface common to all classes, as appropriate. It declares an interface for accessing and managing its child components and optionally 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 and defines behavior for primitive objects in the composition.
- Composite defines behavior for components having children. it stores child components and implements child-related operations in the Component interface.
- Client manipulates objects in the composition through the Component interface.
Composite does not force you to treat all Components as Composites. It merely tells you to put all operations that you want to treat “uniformly” in the Component class. If add, remove, and similar operations cannot, or must not, be treated uniformly, then do not put them in the Component base class. Remember, by the way, that each pattern’s structure diagram does not define the pattern; it merely depicts what in our experience is a common realization thereof. Just because Composite’s structure diagram shows child management operations in the Component base class does not mean all implementations of the pattern must do the same. Visitor pattern can be used to overcome this issue, so enumeration is not a problem - the Visitor knows in each case, exactly what kind of object it’s dealing with. The Visitor doesn’t need every object to provide an enumeration interface.
- The composite pattern applies when there is a part-whole hierarchy of objects and a client needs to deal with objects uniformly regardless of the fact that an object might be a leaf or a branch.
- Graphics Editors use composite pattern to implement complex and simple graphics.
- File System implementations use the composite design pattern (Note that a folder object usually contains one or more file or folder objects and thus is a complex object where a file is a simple object).
- Recursive composition
- Composite lets clients treat individual objects and compositions of objects uniformly.
- The Composite pattern does one thing really well, and that is that it allows you to treat both nodes and leafs in the same way. However, by providing this flexibility and transparency, you're choosing a trade-off on the Single Responsibility principle. This is not necessarily a bad thing, but it's something that you should keep in mind.
- The pattern probably is not ideal to use as a data structure. In cases where the ordering of child nodes is important, you will need to add in extra functionality, perhaps utilizing the Iterator pattern.
- Composite and Decorator have similar structure diagrams, reflecting the fact that both rely on recursive composition to organize an open-ended number of objects.
- Composite can be traversed with Iterator. Visitor can apply an operation over a Composite. Composite could use Chain of Responsibility to let components access global properties through their parent. It could also use Decorator to override these properties on parts of the composition. It could use Observer to tie one object structure to another and State to let a component change its behavior as its state changes.
- Composite can let you compose a Mediator out of smaller pieces through recursive composition.
- Decorator is designed to let you add responsibilities to objects without subclassing. Composite’s focus is not on embellishment but on representation. These intents are distinct but complementary. Consequently, Composite and Decorator are often used in concert.
- Flyweight is often combined with Composite to implement shared leaf nodes.