From: http://www.cnblogs.com/zhenyulu/articles/41829.html
Reference: http://www.dofactory.com/Patterns/PatternComposite.aspx
Define: compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
I. Composite Mode
The merging mode is sometimes called part-whole ). The merging mode organizes objects into the tree structure and can be used to describe the relationship between the whole and the part. The merging mode allows the client to view elements as compound elements.
Talking about Monk stories
This is what my grandmother told me when I was a child: I used to have a mountain, a temple in the mountains, and an old monk in the temple is telling a story to the little monk. What is the story? Once upon a time there was a mountain, and there was a temple in the mountains ....... How many times will Grandma's story be circulated, depending on how long you will fall asleep. There are mountains, temples, monks, and stories in the story. Therefore, there are two types of Role in the story: one has no other roles, and the other has other roles.
Object Tree Structure
A tree structure consists of two types of nodes: tree branches and leaf nodes. Tree branches can have subnodes, but a leaf node cannot have subnodes. Except the root node, other nodes have only one parent node.
Note: A tree branch node does not contain any leaves, but it is still a tree branch node because it has the ability to carry leaves, instead of a leaf node. A leaf node can never contain child nodes.
Ii. Overview of merging Modes
The class diagram is omitted from the details of each role.
It can be seen that the above class graph structure involves three roles:
- Abstract component role: This is an abstract role that specifies an interface for the objects involved in the combination. This role provides a common interface and its default behavior.
- Leaf component (leaf) Role: represents the leaf object that participates in the combination. A leaf object has no sub-objects.
- Composite role: represents the object with sub-objects in the combination, and shows the behavior of the object.
It can be seen that composite objects can contain other component objects. In other words, a composite object can contain other composite or leaf objects.
The implementation of the merging mode is divided into two forms based on the differences between the Implemented interfaces, namely the security mode and the transparent mode. The merging mode does not provide a parent object management method, but the merging mode must provide sub-object management methods (such as add, remove, and getchild) where appropriate ).
Transparent Mode
As the first option, declare all methods in component to manage subclass objects, including add (), remove (), and getchild () methods. The advantage of this is that all component classes have the same interfaces. In the client's view, the difference between a leaf object and a synthetic object disappears at the interface level, and the client can treat all objects at the same level. This is the synthesis mode in transparent form.
The disadvantage of this choice is that it is not safe, because leaf objects and synthetic objects are essentially different. Leaf objects cannot have objects of the next level. Therefore, the add (), remove (), and getchild () methods have no meaning. They do not make errors during compilation, errors only occur during running.
Security Mode
The second option is to declare all methods in the composite class to manage subclass objects. This approach is safe because leaf objects do not have any method to manage subclass objects. Therefore, if the client uses these methods for leaf objects, an error occurs during compilation.
The disadvantage of this choice is that it is not transparent, because the leaf class and the synthesis class will have different interfaces.
These two forms have their own advantages and disadvantages and need to be decided based on the specific circumstances of the software.
Iii. Structure of safe synthesis Mode
The safe synthesis mode requires that the management clustering method only appears in the tree component class, but not in the leaf component.
This form involves three roles:
- Abstract component role: This is an abstract role that defines public interfaces and default actions for the objects involved in the combination and can be used to manage all sub-objects. In a safe synthesis mode, the component role does not define a method for managing sub-objects. This definition is provided by the Branch component object.
- Leaf component (leaf) Role: A leaf object is an object without sub-child objects and defines the behavior of the original objects in the combination.
- Composite role: indicates the object with sub-object in the combination. The branches object provides all methods for managing sub-objects, such as add (), remove (), and getchild.
Iv. Safe synthesis mode implementation
The following sample code demonstrates the safe merging mode code:
// Composite pattern -- Author: rocket5725@163.com <br/> using system; <br/> using system. text; <br/> using system. collections; </P> <p> // "component" <br/> abstract class component <br/> {<br/> // fields <br/> protected string name; </P> <p> // constructors <br/> Public component (string name) <br/> {<br/> This. name = Name; <br/>}</P> <p> // operation <br/> public abstract void display (INT depth ); <br/>}</P> <p> // "composite" <br/> class composite: component <br/>{< br/> // fields <br/> private arraylist children = new arraylist (); </P> <p> // constructors <br/> Public composite (string name): Base (name) {}</P> <p> // methods <br/> Public void add (Component component) <br/>{< br/> children. add (component); <br/>}< br/> Public void remove (Component component) <br/>{< br/> children. remove (component); <br/>}< br/> Public override void display (INT depth) <br/>{< br/> console. writeline (new string ('-', depth) + name ); </P> <p> // display each of the node's children <br/> foreach (Component component in children) <br/> component. display (depth + 2); <br/>}</P> <p> // "leaf" <br/> class leaf: component <br/> {<br/> // constructors <br/> Public leaf (string name): Base (name) {}</P> <p> // methods <br/> Public override void display (INT depth) <br/>{< br/> console. writeline (new string ('-', depth) + name ); <br/>}</P> <p>/**/<br/> /// <summary> <br/> // client Test <br/> // </Summary> <br/> public class client <br/> {<br/> Public static void main (string [] ARGs) <br/>{< br/> // create a tree structure <br/> composite root = new composite ("root"); <br/> root. add (new leaf ("leaf A"); <br/> root. add (new leaf ("leaf B"); <br/> composite comp = new composite ("Composite X"); </P> <p> comp. add (new leaf ("leaf xa"); <br/> comp. add (new leaf ("leaf XB"); <br/> root. add (COMP); </P> <p> root. add (new leaf ("leaf C ")); </P> <p> // add and remove a leaf <br/> leaf L = new leaf ("leaf D"); <br/> root. add (l); <br/> root. remove (l); </P> <p> // recursively display nodes <br/> root. display (1); <br/> console. read (); <br/>}< br/>}
V. Transparent synthesis mode structure
Different from the safe synthesis mode, the transparent synthesis mode requires that all specific component classes, regardless of the branches or leaves, comply with a fixed interface.
This form involves three roles:
- Abstract component role: This is an abstract role that specifies an interface for the objects to be combined to standardize common interfaces and default behaviors.
- Leaf component (leaf) Role: this role represents the leaf objects that participate in the combination and defines the behavior of the original objects that participate in the combination. The leaf class provides mediocre implementation of methods used to manage sub-classes on objects, such as add (), remove (), and getchild.
- Composite role: represents the object with sub-objects in the combination and defines the behavior of such objects.
Vi. Transparent synthesis mode implementation
The following sample code demonstrates the safe merging mode code:
// Composite pattern -- Author: rocket5725@163.com <br/> using system; <br/> using system. text; <br/> using system. collections; </P> <p> // "component" <br/> abstract class component <br/> {<br/> // fields <br/> protected string name; </P> <p> // constructors <br/> Public component (string name) <br/> {This. name = Name ;}</P> <p> // methods <br/> Abstract Public void add (component C ); <br/> Abstract Public void remove (component C); <br/> Abstract Public void display (INT depth ); <br/>}</P> <p> // "composite" <br/> class composite: component <br/>{< br/> // fields <br/> private arraylist children = new arraylist (); </P> <p> // constructors <br/> Public composite (string name): Base (name) {}</P> <p> // methods <br/> Public override void add (Component component) <br/> {children. add (Component) ;}</P> <p> Public override void remove (Component component) <br/> {children. remove (Component) ;}</P> <p> Public override void display (INT depth) <br/>{< br/> console. writeline (new string ('-', depth) + name ); </P> <p> // display each of the node's children <br/> foreach (Component component in children) <br/> component. display (depth + 2); <br/>}</P> <p> // "leaf" <br/> class leaf: component <br/> {<br/> // constructors <br/> Public leaf (string name): Base (name) {}</P> <p> // methods <br/> Public override void add (component C) <br/> {console. writeline ("cannot add to a leaf") ;}</P> <p> Public override void remove (component C) <br/> {console. writeline ("cannot remove from a leaf") ;}</P> <p> Public override void display (INT depth) <br/> {console. writeline (new string ('-', depth) + name );} <br/>}</P> <p>/**/<br/> // <summary> <br/> // client test <br/>/ // </Summary> <br/> public class client <br/> {<br/> Public static void main (string [] ARGs) <br/>{< br/> // create a tree structure <br/> composite root = new composite ("root"); <br/> root. add (new leaf ("leaf A"); <br/> root. add (new leaf ("leaf B"); <br/> composite comp = new composite ("Composite X"); </P> <p> comp. add (new leaf ("leaf xa"); <br/> comp. add (new leaf ("leaf XB"); <br/> root. add (COMP); </P> <p> root. add (new leaf ("leaf C ")); </P> <p> // add and remove a leaf <br/> leaf L = new leaf ("leaf D"); <br/> root. add (l); <br/> root. remove (l); </P> <p> // recursively display nodes <br/> root. display (1); <br/> console. read (); <br/>}< br/>}
7. Several considerations when using the merging mode
- Obviously, the reference of the parent object is given. The parent object reference is provided in the sub-object, which can easily traverse all parent objects. With this reference, you can easily apply the responsibility chain mode.
- In a general system, you can share components using the metadata mode. However, because the objects in the merging mode often have references to the parent object, sharing is not easy to implement.
- Sometimes the system needs to traverse the child component of a tree branch structure for many times. At this time, you can consider storing the result of traversing the child component in the parent component as a cache.
- Regarding the data type used to store sub-objects, arraylist is used in schematic code, and other clustering or arrays can be used in the actual system.
- The client tries its best not to directly call methods in the leaf class, but to use the polymorphism of its parent class (Component) to complete the call, which can increase code reusability.
8. Monk stories
IX. An example of practical application of the composite mode
The following is an application that demonstrates some basic image elements (such as straight lines and gardens) and some composite image elements (composed of basic image elements) the process of building a complex Graphic Tree.
// Composite pattern -- Author: rocket5725@163.com </P> <p> using system; <br/> using system. collections; </P> <p> // "component" <br/> abstract class drawingelement <br/> {<br/> // fields <br/> protected string name; </P> <p> // constructors <br/> Public drawingelement (string name) <br/> {This. name = Name ;}</P> <p> // operation <br/> Abstract Public void display (INT indent ); <br/>}</P> <p> // "leaf" <br/> class primitiveelement: drawingelement <br/>{< br/> // constructors <br/> Public primitiveelement (string name): Base (name) {}</P> <p> // operation <br/> Public override void display (INT indent) <br/>{< br/> console. writeline (new string ('-', indent) + <br/> "draw a {0}", name ); <br/>}</P> <p> // "composite" <br/> class compositeelement: drawingelement <br/>{< br/> // fields <br/> private arraylist elements = new arraylist (); </P> <p> // constructors <br/> Public compositeelement (string name): Base (name) {}</P> <p> // methods <br/> Public void add (drawingelement d) <br/> {elements. add (d) ;}</P> <p> Public void remove (drawingelement d) <br/> {elements. remove (d) ;}</P> <p> Public override void display (INT indent) <br/>{< br/> console. writeline (new string ('-', indent) + <br/> "+" + name ); </P> <p> // display each child element on this node <br/> foreach (drawingelement C in elements) <br/> C. display (indent + 2 ); <br/>}</P> <p>/**/<br/> /// <summary> <br/> // compositeapp Test <br/> // </Summary> <br/> public class compositeapp <br/> {<br/> Public static void main (string [] ARGs) <br/>{< br/> // create a tree structure <br/> compositeelement root = new <br/> compositeelement ("picture"); <br/> root. add (New primitiveelement ("Red Line"); <br/> root. add (New primitiveelement ("Blue Circle"); <br/> root. add (New primitiveelement ("Green Box"); </P> <p> compositeelement comp = new <br/> compositeelement ("two circles "); <br/> comp. add (New primitiveelement ("black circle"); <br/> comp. add (New primitiveelement ("White Circle"); <br/> root. add (COMP); </P> <p> // add and remove a primitiveelement <br/> primitiveelement L = new primitiveelement ("Yellow Line "); <br/> root. add (l); <br/> root. remove (l); </P> <p> // recursively display nodes <br/> root. display (1); <br/> console. read (); <br/>}< br/>}
The merging mode is related to many other modes and will be introduced later.