Design mode [combination mode], the perfect solution for tree structure

1. What is the combination mode

The Composite Pattern is also known as the Part-Whole pattern. Its purpose is to express a single object (leaf node) and a composite object (twig node) with the same interface, so that customers can It is consistent with the use of composite objects and belongs to the structural mode.

The Composite pattern 树形结构composes objects in terms of objects, representing part and whole hierarchies. `

GOF24 original text: Combining objects into a tree structure to represent a "part-whole" hierarchy allows users to have consistency in the use of individual objects and composite objects.

The design idea of ​​the combination mode is not so much a design mode as an abstraction of data structures and algorithms for business scenarios. Among them, data can be expressed as a data structure such as a tree, and business requirements can be realized through a recursive traversal algorithm on the tree. Combination mode organizes a group of objects into a tree structure, treats both individual objects and composite objects as nodes in the tree to unify the processing logic, and it uses the characteristics of the tree structure to process each subtree recursively, simplifying in turn Code. 使用组合模式的前提在于,你的业务场景必须能够表示成树形结构。所以,组合模式的应用场景也比较局限,它并不是一种很常用的设计模式.

1. Three roles in combination mode

The combination mode is generally used to describe the relationship between the whole and the part. It organizes objects into a tree structure. The topmost node is called the root node. The root node can contain branch nodes and leaf nodes, and the branch nodes can contain branch nodes. and leaf nodes. As shown in the figure below:
insert image description here
As can be seen from the above figure, the root node and the branch node are essentially the same data type and can be used as a container: while the leaf node and the branch node are not of the same type semantically, but in the combination mode In , the branch nodes and leaf nodes will be considered as the same data type (defined with the same interface), so that they have consistent behavior. In this way, in the combination mode, the objects in the entire tree structure are of the same type, which brings a benefit that customers do not need to distinguish between branch nodes or leaf nodes, but can directly operate, which brings great benefits to customers. convenient.

Combination mode contains 3 roles:

  • Abstract root node (Component): defines the common methods and properties of objects at all levels of the system, and can pre-define some default behaviors and properties;
  • Branch node (Composite): define the behavior of branch nodes, store child nodes, and combine branch nodes and leaf nodes to form a tree structure;
  • Leaf node (Leaf): Leaf node object, there is no branch under it, and it is the smallest unit of system hierarchy traversal.

There are two different ways to implement the combination mode in code, namely 透明组合模式和安全组合模式.

2. Combination mode application scenarios

When the subsystem and its object levels present a tree structure, the composition mode can be used to make the behavior and operation of each object level in the subsystem consistent. When the client uses any hierarchical object in the subsystem, there is no need to distinguish, and the general operation can be used directly, which provides convenience for the use of the client.

(1) When it is hoped that the client can ignore the difference between a combined object and a single object;
(2) The object hierarchy has a whole and a part, and has a tree structure.

Commonly used combination mode scenarios:
tree menu; operating system directory structure; company organizational structure, etc.
insert image description here

3. Precautions and details of combination mode

(1) Simplify client operations. Clients only need to deal with consistent objects without considering whole parts or node leaves.
(2) 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.
(3) It is convenient to create complex hierarchical structures. The client does not need to care about the composition details in the combination, and can easily add nodes or leaves to create a complex tree structure.
(4) Combination mode is very suitable for traversing organizations, or processing objects with a tree structure.
(5) Higher abstraction is required, if 节点和叶子有很多差异性的话, for example, many methods and attributes are different, 不适合使用组合模式.

2. Transparent combination mode

The transparent composition mode is to define all public methods in Component. The advantage of this is that the client does not need to distinguish between leaf nodes (Leaf) and branch nodes (Composite), and they have completely consistent interfaces. Its UML class diagram is as follows:
insert image description here

1. Cases of colleges and departments

Let's take the departmental structure of a school as an example. A school has multiple colleges, and a college has multiple departments.

First define the abstract root node:

// 抽象根节点
public abstract class OrganizationComponent {
    
    

	private String name; // 名字
	private String des; // 说明
	
	protected  void add(OrganizationComponent organizationComponent) {
    
    
		//默认实现
		throw new UnsupportedOperationException();
	}
	
	protected  void remove(OrganizationComponent organizationComponent) {
    
    
		//默认实现
		throw new UnsupportedOperationException();
	}

	//构造器
	public OrganizationComponent(String name, String des) {
    
    
		super();
		this.name = name;
		this.des = des;
	}
	// 省略 get  set
	
	//方法print, 做成抽象的, 子类都需要实现
	protected abstract void print();
	
}

University:

//University 就是 Composite , 可以管理College
public class University extends OrganizationComponent {
    
    
	// 定义学院集合 College
	List<OrganizationComponent> organizationComponents = new ArrayList<OrganizationComponent>();

	// 构造器
	public University(String name, String des) {
    
    
		super(name, des);
	}

	// 重写add
	@Override
	protected void add(OrganizationComponent organizationComponent) {
    
    
		organizationComponents.add(organizationComponent);
	}

	// 重写remove
	@Override
	protected void remove(OrganizationComponent organizationComponent) {
    
    
		organizationComponents.remove(organizationComponent);
	}

	@Override
	public String getName() {
    
    
		return super.getName();
	}

	@Override
	public String getDes() {
    
    
		return super.getDes();
	}

	// print方法,就是输出University 包含的学院
	@Override
	protected void print() {
    
    
		System.out.println("--------------" + getName() + "--------------");
		//遍历 organizationComponents 
		for (OrganizationComponent organizationComponent : organizationComponents) {
    
    
			organizationComponent.print();
		}
	}
}

College:

public class College extends OrganizationComponent {
    
    

	//List 中 存放的Department
	List<OrganizationComponent> organizationComponents = new ArrayList<OrganizationComponent>();

	// 构造器
	public College(String name, String des) {
    
    
		super(name, des);
	}

	// 重写add
	@Override
	protected void add(OrganizationComponent organizationComponent) {
    
    
		//  将来实际业务中,Colleage 的 add 和  University add 不一定完全一样
		organizationComponents.add(organizationComponent);
	}

	// 重写remove
	@Override
	protected void remove(OrganizationComponent organizationComponent) {
    
    
		organizationComponents.remove(organizationComponent);
	}

	@Override
	public String getName() {
    
    
		return super.getName();
	}

	@Override
	public String getDes() {
    
    
		return super.getDes();
	}

	// print方法,就是输出University 包含的学院
	@Override
	protected void print() {
    
    
		System.out.println("--------------" + getName() + "--------------");
		//遍历 organizationComponents 
		for (OrganizationComponent organizationComponent : organizationComponents) {
    
    
			organizationComponent.print();
		}
	}
}

Major (leaf node):

public class Department extends OrganizationComponent {
    
    

	//没有集合
	
	public Department(String name, String des) {
    
    
		super(name, des);
	}

	//add , remove 就不用写了,因为他是叶子节点
	@Override
	public String getName() {
    
    
		return super.getName();
	}
	
	@Override
	public String getDes() {
    
    
		return super.getDes();
	}
	
	@Override
	protected void print() {
    
    
		System.out.println(getName());
	}
}

Test class:

public class Client {
    
    

	public static void main(String[] args) {
    
    
		// TODO Auto-generated method stub
		
		//从大到小创建对象 学校
		OrganizationComponent university = new University("清华大学", " 中国顶级大学 ");
		
		//创建 学院
		OrganizationComponent computerCollege = new College("计算机学院", " 计算机学院 ");
		OrganizationComponent infoEngineercollege = new College("信息工程学院", " 信息工程学院 ");
		
		
		//创建各个学院下面的系(专业)
		computerCollege.add(new Department("软件工程", " 软件工程不错 "));
		computerCollege.add(new Department("网络工程", " 网络工程不错 "));
		computerCollege.add(new Department("计算机科学与技术", " 计算机科学与技术是老牌的专业 "));
		
		//
		infoEngineercollege.add(new Department("通信工程", " 通信工程不好学 "));
		infoEngineercollege.add(new Department("信息工程", " 信息工程好学 "));
		
		//将学院加入到 学校
		university.add(computerCollege);
		university.add(infoEngineercollege);
		
		//university.print();
		university.print();
	}

}

The final UML class diagram is as follows:
insert image description here

2. Summary of transparent combination mode

The transparent composition mode defines all public methods in Component. The advantage of this is that the client does not need to distinguish between the leaf node (Leaf) and the branch node (Composite), which have exactly the same interface; the disadvantage is that the leaf node (Leaf) will Inheritance gets some methods it does not need (methods to manage subclass operations), which violates the design pattern interface segregation principle.

3. Security combination mode

The security composition mode only stipulates the most basic consistent behavior of each level of the system, and puts the method of the composition (tree node) itself (management of adding and deleting subclass objects, etc.) into itself. Its UML class diagram is as follows:
insert image description here

1. Case of linux directory system

The file system has two layers: folders and files. Among them, folders can hold files, which are branch nodes; files are leaf nodes. Since the directory system has fewer layers, and the structure of branch nodes (folders) is relatively stable, and files can actually have many types, here we choose to use the security combination mode to implement the directory system, which can avoid introducing redundancy for leaf types (files). method.

// 顶层抽象
public abstract class Directory {
    
    

    protected String name;

    public Directory(String name) {
    
    
        this.name = name;
    }

    public abstract void show();
}
// 目录
public class Folder extends Directory {
    
    
    private List<Directory> dirs;

    private Integer level;

    public Folder(String name,Integer level) {
    
    
        super(name);
        this.level = level;
        this.dirs = new ArrayList<Directory>();
    }

    @Override
    public void show() {
    
    
        System.out.println(this.name);
        for (Directory dir : this.dirs) {
    
    
            //控制显示格式
            if(this.level != null){
    
    
                for(int  i = 0; i < this.level; i ++){
    
    
                    //打印空格控制格式
                    System.out.print("  ");
                }
                for(int  i = 0; i < this.level; i ++){
    
    
                    //每一行开始打印一个+号
                    if(i == 0){
    
     System.out.print("+"); }
                    System.out.print("-");
                }
            }
            //打印名称
            dir.show();
        }
    }

    public boolean add(Directory dir) {
    
    
        return this.dirs.add(dir);
    }

    public boolean remove(Directory dir) {
    
    
        return this.dirs.remove(dir);
    }

    public Directory get(int index) {
    
    
        return this.dirs.get(index);
    }

    public void list(){
    
    
        for (Directory dir : this.dirs) {
    
    
            System.out.println(dir.name);
        }
    }

}
// 文件
public class File extends Directory {
    
    

    public File(String name) {
    
    
        super(name);
    }

    @Override
    public void show() {
    
    
        System.out.println(this.name);
    }

}
// 测试类
class Test {
    
    
    public static void main(String[] args) {
    
    

        System.out.println("============安全组合模式===========");

        File qq = new File("QQ.exe");
        File wx = new File("微信.exe");

        Folder office = new Folder("办公软件",2);

        File word = new File("Word.exe");
        File ppt = new File("PowerPoint.exe");
        File excel = new File("Excel.exe");

        office.add(word);
        office.add(ppt);
        office.add(excel);

        Folder wps = new Folder("金山软件",3);
        wps.add(new File("WPS.exe"));
        office.add(wps);

        Folder root = new Folder("根目录",1);
        root.add(qq);
        root.add(wx);
        root.add(office);

        System.out.println("----------show()方法效果-----------");
        root.show();

        System.out.println("----------list()方法效果-----------");
        root.list();
    }
}

Let's take a look at the UML class diagram:
insert image description here

2. Summary of security combination mode

The advantage of the security composite mode is that the responsibility of the interface definition is clear, which conforms to the single responsibility principle of the design mode and the interface isolation principle; the disadvantage is that the customer needs to distinguish between the branch node (Composite) and the leaf node (Leaf), so as to correctly handle the operations of each level, the client Unable to rely on abstraction (Component), which violates the design pattern dependency inversion principle.

Fourth, the combination mode used in the source code

1、HashMap

Map is an abstract construction (at the same time, this construction only supports the storage format of key-value pairs), while HashMap is an intermediate construction, and the Node nodes in HashMap are leaf nodes.

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {
    
    
    // ...
	transient Node<K,V>[] table;
	// ...
}	

static class Node<K,V> implements Map.Entry<K,V> {
    
    
    final int hash;
    final K key;
    V value;
    Node<K,V> next;
}

The input parameter of its putAll method is Map:

public void putAll(Map<? extends K, ? extends V> m) {
    
    
    putMapEntries(m, true);
}

2、ArrayList

The addAll method of ArrayList, its parameter is also the parent class Collection:

public boolean addAll(Collection<? extends E> c) {
    
    
    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // Increments modCount
    System.arraycopy(a, 0, elementData, size, numNew);
    size += numNew;
    return numNew != 0;
}

3、MyBatis

MyBatis parses the SQL in various Mapping files, and designs a very critical class called SqlNode. Each Node in the xml will be parsed into a SqlNode object, and finally all the SqlNodes are assembled together to form a complete SQL statement. , its top-level design is very simple. Look at the source code:

public interface SqlNode {
    
    
  boolean apply(DynamicContext context);
}

The Apply method will analyze the SQL fragment recorded by the SqlNode according to the parameter context passed in, and call the DynamicContext.appendSql() method to append the parsed SQL fragment to the SqlBuilder of the DynamicContext for storage. After all SqlNodes under the SQL node have finished parsing, a complete SQL statement can be obtained through DynamicContext.getSql().

Let's look at the class diagram:
insert image description here

Guess you like

Origin blog.csdn.net/A_art_xiang/article/details/130606421