Combination mode
Business requirements
- The school displays the structure of colleges and departments. A school has multiple colleges and a college has multiple departments;
- Traditional thinking, the Department inherits the college, and the college inherits the school;
problem analysis
- The college is regarded as a subclass of the school, and the Department is a subclass of the college. In fact, it is hierarchical based on the size of the organization
- In fact, our requirement is that a school has multiple colleges and a college has multiple departments; The traditional scheme can not well realize management operations, such as adding, deleting and traversing colleges and departments
- Solution: regard schools, colleges and departments as organizational structures. There is no inheritance relationship between them, but a tree structure, which can better realize management operation
Basic introduction
- Combination mode, also known as partial whole mode, creates a tree structure of object groups, combines objects into a tree structure, and represents the hierarchical relationship between whole and part
- Combination mode is a tree structure to combine objects, which is used to represent part and whole levels
- This type of design pattern belongs to structural pattern
- The combination mode is that users have consistent access to single objects and combined objects, that is, the combination allows customers to deal with individual objects and combined objects in a consistent way
Schematic description
- Component: This is the object declaration interface in the composition. If appropriate, it implements the default behavior of the interface common to all classes. It is used to access and manage component subcomponents. It can make abstract classes or interfaces
- Leaf: represents a leaf node in a combination. A leaf node has no child nodes and acts as a managed person
- Composite: non leaf node, used to store sub components and implement related operations of sub components in the Component interface, such as adding and deleting; Act as manager
Problems solved - Composite mode solves such problems. When the object we want to deal with can generate a tree structure, and we want to operate on the nodes and leaves of the tree, it can provide a consistent way, regardless of whether it is a node or a leaf
code implementation
Organization parent class, which can be general class, abstract class and interface
The method implemented by default determines whether the parent method can be used according to whether the lower node is a leaf node
@Data public abstract class OrganizationComponent { private String name; private String des; public OrganizationComponent(String name, String des) { super(); this.name = name; this.des = des; } protected void add(OrganizationComponent organizationComponent) { // Default implementation throw new UnsupportedOperationException(); } protected void remove(OrganizationComponent organizationComponent) { // Default implementation throw new UnsupportedOperationException(); } // Subclasses need to be implemented protected abstract void print(); }
Define university classes
public class University extends OrganizationComponent{ List<OrganizationComponent> list = new ArrayList<>(); public University(String name, String des) { super(name, des); } @Override protected void add(OrganizationComponent organizationComponent) { list.add(organizationComponent); } @Override protected void remove(OrganizationComponent organizationComponent) { list.remove(organizationComponent); } // Output the colleges contained in the current University @Override protected void print() { System.out.println("============="+getName()+"==============="); for (OrganizationComponent o : list) { o.print(); } } }
Define college class
public class College extends OrganizationComponent{ List<OrganizationComponent> list = new ArrayList<>(); public College(String name, String des) { super(name, des); } @Override protected void add(OrganizationComponent organizationComponent) { list.add(organizationComponent); } @Override protected void remove(OrganizationComponent organizationComponent) { list.remove(organizationComponent); } // Output the colleges contained in the current College @Override protected void print() { System.out.println("============="+getName()+"==============="); for (OrganizationComponent o : list) { o.print(); } } }
Define specific system
public class Department extends OrganizationComponent{ public Department(String name, String des) { super(name, des); } // The leaf node does not have add / delete, and add and remove are no longer rewritten @Override protected void print() { System.out.println(getName()); } }
client
public class Client { public static void main(String[] args) { // Create a school OrganizationComponent university = new University("Tsinghua University", "Famous Chinese Schools"); // Create College OrganizationComponent computerCollege = new College("school of computing", "school of computing"); OrganizationComponent infoEngineerCollege = new College("School of Information Engineering", "School of Information Engineering"); // Create system computerCollege.add(new Department("software engineering", "Software engineering is really good")); computerCollege.add(new Department("Network engineering", "Network engineering is also good")); computerCollege.add(new Department("Computer science and technology", "Computer science and technology can also")); infoEngineerCollege.add(new Department("communication engineering", "Communication engineering is not easy to learn")); infoEngineerCollege.add(new Department("Information Engineering", "Information engineering is too difficult")); // Add college to school university.add(computerCollege); university.add(infoEngineerCollege); // If you need to view which level, you can output it directly university.print(); System.out.println("##################Split line####################"); computerCollege.print(); } }
JDK source code analysis - HashMap
Demo
public class Composite { public static void main(String[] args) { Map<Integer, String> hashMap = new HashMap<>(); // Save to leaf node hashMap.put(0, "Water Margin"); Map<Integer, String> map = new HashMap<>(); map.put(1, "Journey to the West"); map.put(2, "The Dream of Red Mansion"); // Storage node hashMap.putAll(map); System.out.println(hashMap); } }
Source code fragment
public interface Map<K, V> { ... V put(K var1, V var2); ... void putAll(Map<? extends K, ? extends V> var1);
public abstract class AbstractMap<K,V> implements Map<K,V> { ... public V put(K key, V value) { throw new UnsupportedOperationException(); } ... public void putAll(Map<? extends K, ? extends V> m) { for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) put(e.getKey(), e.getValue()); } }
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable { ... public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } ... final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; ... return null; } ... static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Node<K,V> next; Node(int hash, K key, V value, Node<K,V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } public final K getKey() { return key; } public final V getValue() { return value; } public final String toString() { return key + "=" + value; } public final int hashCode() { return Objects.hashCode(key) ^ Objects.hashCode(value); } public final V setValue(V newValue) { V oldValue = value; value = newValue; return oldValue; } public final boolean equals(Object o) { if (o == this) return true; if (o instanceof Map.Entry) { Map.Entry<?,?> e = (Map.Entry<?,?>)o; if (Objects.equals(key, e.getKey()) && Objects.equals(value, e.getValue())) return true; } return false; } } }
explain
- Map is an abstract build (similar to the previous Component)
- HashMap is a Composite that implements / inherits the relevant method put/putAll
- Node is a static internal class of HashMap, similar to Leaf node, without put/putAll
Pay attention to implementation and details
- Simplify the client operation. The client only needs to face consistent objects without considering the whole part or leaf node
- 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
- It is convenient to create a complex hierarchy. The client does not care about the composition details in the composition. It is easy to add nodes or leaves to create a complex tree structure
- When you need to traverse the organization, or when the object you are dealing with has an attribute structure, it is very suitable to use the composite pattern
- It requires high abstraction. If there are many differences between nodes and leaves, such as different methods and attributes, it is not suitable to use composite mode