catalogue
2. Precautions and details of combination mode
4.1} transparent combination mode
5. Application example of combined mode:
6. Application of combination mode in java HashMap source code
1. Basic introduction:
1) Composite Pattern, also known as partial overall pattern, is a pattern that combines objects into a tree hierarchy, and combines objects into a tree structure to represent the hierarchical relationship of "whole part".
2) The combination mode combines objects according to the tree structure, which is used to represent the partial and overall levels.
3) This type of design pattern belongs to structural pattern.
4) The combination mode makes the user's access to single objects and combined objects consistent, that is, the combination allows the customer to deal with individual objects and combined objects in a consistent way.
The combination mode is generally used to describe the relationship between the whole and the part. It organizes the objects into a tree structure. The top-level node is called the root node. The root node can contain branch nodes and leaf nodes, and the branch node and leaf nodes can be contained below the branch node. The tree structure is shown below.
As can be seen from the above figure, the root node and branch node are essentially the same data type and can be used as containers; Leaf nodes and branch nodes do not belong to the same type semantically. However, in the composite mode, the branch node and leaf node will be regarded as belonging to the same data type (defined with a unified interface), so that they have consistent behavior. In this way, in the combination mode, the objects in the whole tree structure belong to the same type, which brings the advantage that users do not need to distinguish whether it is a branch node or a leaf node, and can operate directly, which brings great convenience to users.
2. Precautions and details of combination mode
2.1 advantages
- Simplify client operations. Composite mode enables client code to deal with single objects and composite objects consistently, regardless of whether they are dealing with single objects or composite objects.
- It has strong scalability. When we want to change the composite object, we only need to adjust the internal hierarchical relationship, and the client does not need to make any changes to meet the "opening and closing principle".
- Facilitate the creation of complex hierarchies. The client does not care about the composition details in the composition, and it is easy to add nodes or leaves to create a complex tree structure
- When the organization needs to be traversed, or the object to be processed has a tree structure, it is very suitable to use the combination mode
2.2 disadvantages
- It requires high abstraction. If there are many differences between nodes and leaves, for example, many methods and attributes are different, it is not suitable to use composite mode
- The design is complex, and the client needs to spend more time to clarify the hierarchical relationship between classes;
- It is not easy to limit the components in the container;
- It is not easy to add new functions of components by inheritance;
3. Structure of mode
The composite pattern contains the following main roles.
- Abstract Component role: its main role is to declare public interfaces for leaf components and branch components and implement their default behavior. In the transparent composition mode, the abstract Component also declares the interface to access and manage subclasses; In the safe composite mode, the interface for accessing and managing subclasses is not declared, and the management is completed by the branch Component. (general abstract classes or interfaces, defining some general methods, such as adding and deleting)
- Leaf role: it is a leaf node object in the composition. It has no child nodes and is used to inherit or implement abstract components.
- Composite role / intermediate component: it is a branch node object in the composition. It has child nodes, which are used to inherit and implement abstract components. Its main function is to store and manage subassemblies, usually including Add(), Remove(), GetChild(), etc.
As shown in the figure below
The combination mode is divided into transparent combination mode and safe combination mode.
3.1} transparent mode
In this way, because the abstract component declares all methods in all subclasses, the client does not need to distinguish between leaf objects and branch objects, which is transparent to the client. But its disadvantage is that the leaf component has no Add(), Remove() and GetChild() methods, but needs to implement them (empty implementation or throwing exceptions), which will bring some security problems. Its structure is shown in Figure 1.
.
3.2 safety mode
In this way, the method of managing sub components is moved to the branch component, and the abstract component and leaf component have no management method for sub objects, which avoids the security problem of the previous method. However, because the leaf and branch have different interfaces, the client needs to know the existence of leaf object and branch object when calling, so it loses transparency. Its structure is shown in Figure 2.
4. Mode implementation:
4.1 # transparent combination mode
The following is the implementation code of transparent composite mode.
public class CompositePattern { public static void main(String[] args) { Component c0 = new Composite(); Component c1 = new Composite(); Component leaf1 = new Leaf("1"); Component leaf2 = new Leaf("2"); Component leaf3 = new Leaf("3"); c0.add(leaf1); c0.add(c1); c1.add(leaf2); c1.add(leaf3); c0.operation(); } } //Abstract component interface Component { public void add(Component c); public void remove(Component c); public Component getChild(int i); public void operation(); } //Leaf component class Leaf implements Component { private String name; public Leaf(String name) { this.name = name; } public void add(Component c) { } public void remove(Component c) { } public Component getChild(int i) { return null; } public void operation() { System.out.println("leaf" + name + ": Be visited!"); } } //Branch member class Composite implements Component { private ArrayList<Component> children = new ArrayList<Component>(); public void add(Component c) { children.add(c); } public void remove(Component c) { children.remove(c); } public Component getChild(int i) { return children.get(i); } public void operation() { for (Object obj : children) { ((Component) obj).operation(); } } }
4.2 safety combination mode
The implementation code of the secure composite mode is similar to that of the transparent composite mode. As long as it is simply modified, the code is as follows.
First, modify the Component code to preserve only the public behavior of the hierarchy.
interface Component { public void operation(); }
5. Application examples of combined mode:
Take the relationship between school and College as an example
Example code:
1. Define the interface:
//Interface, component public interface OrganizationComponent { //add component void add(OrganizationComponent component); //remove component void remove(OrganizationComponent component); //Print information void print(); }
2. Define abstract classes and implement interfaces
public abstract class Organization implements OrganizationComponent { //name protected String name; //describe protected String des; public Organization(String name, String des) { this.name = name; this.des = des; } protected String getName() { return name; } protected String getDes() { return des; } @Override public void add(OrganizationComponent component) { throw new UnsupportedOperationException(); } @Override public void remove(OrganizationComponent component) { throw new UnsupportedOperationException(); } @Override public void print() { } }
3. Definition of University, college, Department (similar structure)
import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; public class University extends Organization { List<OrganizationComponent> components = new ArrayList<>(); public University(String name, String des) { super(name, des); } @Override public void add(OrganizationComponent component) { components.add(component); } @Override public void remove(OrganizationComponent component) { components.remove(component); } @Override public void print() { List<String> collect = components.stream().map(item -> { Organization organization = (Organization) item; return organization.getName(); }).collect(Collectors.toList()); System.out.println("university " + super.getName() + "contains colleges : " + collect.toString()); } } public class College extends Organization{ List<OrganizationComponent> components = new ArrayList<>(); public College(String name, String des) { super(name, des); } @Override public void add(OrganizationComponent component) { components.add(component); } @Override public void remove(OrganizationComponent component) { components.remove(component); } @Override public void print() { List<String> collect = components.stream().map(item -> { Organization organization = (Organization) item; return organization.getName(); }).collect(Collectors.toList()); System.out.println("college " + super.getName() + "contains department : " + collect.toString()); } } public class Department extends Organization { public Department(String name, String des) { super(name, des); } @Override public void print() { System.out.println(super.getName()); } }
4. Call
public class Client { public static void main(String[] args) { //Build the organizational tree of the school and related colleges and departments OrganizationComponent component = new University("Northwest Agricultural University","Not bad"); //Construction College OrganizationComponent computerCollege = new College("school of computing","Very good"); //Construction line OrganizationComponent programmingDepartment = new Department("Software programming","fucking great"); OrganizationComponent softwareDesignDepartment = new Department("software design ","More awesome"); computerCollege.add(programmingDepartment); computerCollege.add(softwareDesignDepartment); programmingDepartment.print(); System.out.println("========"); OrganizationComponent informationCollege = new College("Institute of information technology","Very good!!!"); OrganizationComponent communicationDepartment = new Department("communication engineering","That's awesome"); OrganizationComponent communicationDesignDepartment = new Department("Communication design","More awesome"); informationCollege.add(communicationDepartment); informationCollege.add(communicationDesignDepartment); informationCollege.print(); System.out.println("========"); //Component school component.add(computerCollege); component.add(informationCollege); component.print(); } }
6. Application of combination mode in java HashMap source code
From the simplified source code of the HashMap class below, we can see that the Map object is passed in the putAll() method. The Map here is an abstract component. At the same time, this component only supports the storage format of key value pairs, while HashMap is an intermediate component, and the Node node in HashMap is the leaf Node.
As shown in the following UML class diagram:
Part of the source code is as follows:
1. Define the interface Map, and define the method in the Map
public interface Map<K, V> { //Define relevant methods int size(); boolean isEmpty(); ...... }
2. Define the abstract class and implement the Map method
public abstract class AbstractMap<K,V> implements Map<K,V> { public int size() { return entrySet().size(); } public boolean isEmpty() { return size() == 0; } }
3. Define HashMap
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable { //HashMap contains Node static inner class (leaf) static class Node<K,V> implements Map.Entry<K,V> { } public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } //Accept a Map public void putAll(Map<? extends K, ? extends V> m) { putMapEntries(m, true); } }