I walk very slowly, but I never walk backwards 
Copy the code

Design pattern – Composition pattern


Become as

Hello, everyone, I am silent, in this class, we will talk about the combination of design patterns, old rules, first of all, we need to introduce a case

Case demonstration – Institutional demonstration

Show the composition of the school’s departments in one page

A school will have more than one school, a college will have more than one major

Write programs to fulfill requirements

Solution 1: General implementation

In the easiest way to think of, which would be inheritance, we define a school with subclasses of schools, each of which has a major, to display the page, which is actually hierarchical in terms of organizational size, as shown in the class diagram below



But if you think about it, is there really a succession relationship between a school and a college? In fact, our requirement is to display the composition of schools and departments in one page. A school has multiple schools and a school has multiple majors. Therefore, such a scheme cannot be well implemented in management operations, such as the addition, deletion and traversal of college majors


A more appropriate way is actually contain the school college, college professional, should be a kind of combination relationship, we can change a way of thinking, as all schools, colleges, professional structure, no inheritance relationship between them, but a tree structure, can better realize the management operation, actually this kind of thinking is the portfolio model, the following, Let’s take a look at the basic introduction of composition patterns

Basic introduction

Composite Pattern, also known as the partial whole Pattern, creates a tree structure of object groups and combines objects into tree structures to represent the “whole-part” hierarchical relationship


The composite pattern combines objects based on a tree structure, which is used to represent both part and whole hierarchies

The composition pattern enables users to have consistent access to both individual objects and composite objects. That is, composition enables customers to work with both individual objects and composite objects in a consistent manner

The principle of class diagram

Next, let’s take a look at the principle class diagram of the composite pattern and sort out the roles in the composite pattern



Combined mode roles

  • Component: This is the object declaration interface in the composite pattern that implements the default interface behavior common to all classes, where appropriate, for accessing and managing Component children, which can be abstract classes or interfaces

  • Leaf: represents the Leaf node in the combination. Leaf node has no child nodes and is the last data storage structure

  • Composite: non-leaf node used to store child parts and perform operations on them in the Component interface, such as add and remove.

Problems solved by composite patterns

The composite pattern solves scenarios where the object we are dealing with can generate a tree structure and we need to operate on nodes and leaves in the tree in a consistent way, regardless of whether it is a node or a leaf



Solution 2: Composite pattern

Class diagrams show

Next, we use the combination mode to solve the problem of college display. First of all, we draw the principle class diagram to analyze the ideas



Code demo
/** * @className OrganizationComponent * @created by silent * @description I walk very slowly, but I never walk backwards */ public abstract class OrganizationComponent { private String name; private String desc; / / describe the public void the add (OrganizationComponent component) {/ / the default implementation throws an abnormal does not support the operation of the throw new UnsupportedOperationException (); } public void remove (OrganizationComponent component) {/ / the default implementation throws an abnormal does not support the operation of the throw new UnsupportedOperationException (); } public OrganizationComponent(String name, String desc) {this.name = name; this.desc = desc; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; Public abstract void show(); } /** * @class name School * @created by * @description School is a Composite OrganizationComponent {// Constructor public School(String name, String desc) {super(name, desc); List<OrganizationComponent> componentList = new ArrayList<>(); // Override public void add(OrganizationComponent component) {componentList.add(component); } // Override public void remove(OrganizationComponent component) {componentList.remove(component); } @Override public String getName() { return super.getName(); } @Override public String getDesc() { return super.getDesc(); } @Override public void show() { System.out.println("--- " + getName() + "---"); / / traverse componentList for (OrganizationComponent OrganizationComponent: componentList) {OrganizationComponent. The show (); }}} /** * @classname College * @created by silent * @description I walk very slowly, but I never walk backwards */ public class College extends OrganizationComponent { public College(String name, String desc) { super(name, desc); } // OrganizationComponent> componentList = new ArrayList<>(); Override public void add(OrganizationComponent component) {// In the future, Collage and School are added in different ways. Each has its own business logic componentList.add(Component); } // Override public void remove(OrganizationComponent component) {componentList.remove(component); } @Override public String getName() { return super.getName(); } @Override public String getDesc() { return super.getDesc(); } @Override public void show() { System.out.println("--- " + getName() + "---"); / / traverse componentList for (OrganizationComponent OrganizationComponent: componentList) {OrganizationComponent. The show (); }}} /** * @className Major * @created by static * @description Major */ public class Major extends OrganizationComponent{ public Major(String name, String desc) { super(name, desc); } Override public String getName() {return super.getName();} Override public String getName(); } @Override public String getDesc() { return super.getDesc(); } @Override public void show() { System.out.println(getName()); }} /** * @className Client * @created by static * @description Client */ public class Client {public static void OrganizationComponent School = new School(" Tsinghua University ", "China's top university "); OrganizationComponent computerCollege = New College(" Computer School ", "Computer School "); // Create a College and add it to your school. OrganizationComponent infoCollege = New College(" School of Information Engineering ", "School of Information Engineering "); school.add(computerCollege); school.add(infoCollege); Add (New Major(" Computer Science and Technology "," Computer Science and Technology ")); ComputerCollege. Add (New Major(" Software Engineering "," Software Engineering ")); Computercollege. add(New Major(" Cyberspace Security "," Cyberspace Security ")); Infocollege. add(New Major(" Communications and information Systems "," Communications and information Systems ")); Infocollege. add(New Major(" Signal processing "," Signal processing ")); Infocollege. add(New Major(" Information Networks and Complex Systems "," Information Networks and Complex Systems ")); school.show(); }}Copy the code

Suppose I don’t care about the whole university, I only care about the situation of a certain college, I just need to call the show() method of the corresponding college, which is convenient and very flexible. If we add a new hierarchical relationship, we only need to inherit the OrganizationComponent, aggregate, and rewrite the business method in it. (Add, remove, show), so let’s talk about the advantages of using composite patterns to solve case problems

Advantages of combination mode
  • The composite pattern allows client code to work consistently with both single and composite objects, regardless of whether it is working with a single object or composite object, shielding the hierarchical differences of the object system and using consistent behavior to control different layers

  • Very high scalability, can easily add branch nodes and leaf nodes objects, and no intrusion on the existing class library, meet the “open and closed principle”

Disadvantages of composite mode

It requires high abstraction. If leaves and nodes have many differences, for example, many attributes and methods are different, it is not suitable to use the combination mode. However, this case shows that many of their attributes and methods are common, similar to a tree structure

Usage scenarios

  • When dealing with similar tree structures with uniform behavior (e.g., operating system directory structure, company organizational structure, etc.)

  • Want to represent the partial-whole hierarchy of objects, typically such as file and folder management

(A file system is made up of files and directories. Each file contains contents, and the contents of each directory can have files and directories. Directories are like a combination of single objects or a combination of objects.

HashMap source code analysis

The composite pattern is used in Java’s collection class, HashMap. Let’s use a test code to analyze the source code

public class Test { public static void main(String[] args) { HashMap<String, String> hashMap = new HashMap<>(); Hashmap.put (" Chapter 1 "," Principle "); HashMap<String, String> map = new HashMap<>(); Map. put(" section 2 "," explore "); Map. put(" section 3 "," go "); hashMap.putAll(map); System.out.println(hashMap); }}Copy the code
Source code flow analysis

The put() and putAll() methods have interfaces and implementations. Next, HashMap implements the Map interface. And the above method is implemented

Public class implements Map<K,V> implements Map<K,V> Serializable { private static final long serialVersionUID = 362498820763181265L;Copy the code

So a HashMap is a concrete Composite. What about leaf nodes?

Then we look at Node inside the HashMap. You can see that Node is a static inner class inside the HashMap

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;
 }
Copy the code

In fact, Node is the leaf Node in our composite mode. As you can see, Node no longer has put, putAll and other key methods, because it is the leaf Node, which is the last structure to store data, so there are only some default methods



Looking at the implementation of the target method in the HashMap, putVal takes a K and a V and puts it into the HashMap as a Node

 final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
 boolean evict) {
 Node<K,V>[] tab; Node<K,V> p; int n, i;
 if ((tab = table) == null || (n = tab.length) == 0)
 n = (tab = resize()).length;
 if ((p = tab[i = (n - 1) & hash]) == null)
 tab[i] = newNode(hash, key, value, null);
Copy the code

If you can get a sense of this relationship, let’s show it in a class diagram



instructions
  • A Map is an abstract build, the Components of a composite pattern

  • A HashMap is a non-leaf node in a Composite pattern, which is used to store child parts and implement operations on child parts in the Component interface, such as PUT (), putAll(), and so on

  • Node is the leaf Node in the combination mode, which has no implementation of key methods and is the last data storage structure

Next day forecast

OK, this is the end of the composition mode, next section, we will start the study of appearance mode, finally, I hope you can feel the interesting design mode in the process of learning, efficient and happy learning, then we will see you next time ~