Design pattern - composite pattern

Combination mode

definition

  • The objects are combined into a tree structure to represent the hierarchical relationship of "part whole", so that the use of single objects and combined objects is consistent
  • In the composite mode, the tree node and leaf node of the tree structure are regarded as the same data type, so that the client does not need to distinguish whether it is a tree node or a root node

give an example

real life

  • In ancient times, it was impossible for an emperor to manage the country by one person to each common people, by dividing three provinces and six departments, and then dividing down the organizations of States, counties and counties
  • Folders and files for computer file management

General structure

  • Abstract root node Component: defines the common attributes and methods of objects at all levels
  • Branch node Composite: defines the behavior of branch nodes, stores child nodes, and combines branch nodes and leaf nodes to form a tree structure
  • Leaf node leaf: the system traverses the smallest unit without branches

If the composite mode is not used, multiple sets need to be maintained inside the branch node to store other object hierarchies. This construction brings great complexity and non scalability. At the same time, hierarchy differentiation is also required during client access, which will also affect the complexity of the client. The composite pattern extracts the common behaviors of all levels of the system, so that the branch node only needs to maintain a set to store the contents of all levels of the system, and the client does not need to distinguish the levels of the system

Transparent mode:

public abstract class AbsComponent {

    protected String commonState;

    public AbsComponent(String commonState){
        this.commonState = commonState;
    }

    public void operation(){
        throw new UnsupportedOperationException("Operation not supported");
    }

    public AbsComponent getChild(int index){
        throw new UnsupportedOperationException("Getting child nodes is not supported");
    }

    public void addChild(AbsComponent component){
        throw new UnsupportedOperationException("Add operation is not supported");
    }

    public void removeChild(AbsComponent component){
        throw new UnsupportedOperationException("Delete operation is not supported");
    }
    
}
public class Composite extends AbsComponent{

    private final List<AbsComponent> components = new ArrayList<>();

    public Composite(String commonState) {
        super(commonState);
    }

    @Override
    public void operation() {
        System.out.println("Composite operation");
    }

    @Override
    public AbsComponent getChild(int index) {
        return components.get(index);
    }

    @Override
    public void addChild(AbsComponent component) {
        components.add(component);
    }

    @Override
    public void removeChild(AbsComponent component) {
        components.remove(component);
    }
}

public class Leaf extends AbsComponent{

    public Leaf(String commonState) {
        super(commonState);
    }

    @Override
    public void operation() {
        System.out.println("leaf operation");
    }
}

Safe mode:

Take file management as an example

public abstract class Directory {

    protected String name;

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

    public abstract void show();

}
public class File extends Directory {

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

    @Override
    public void show() {
        System.out.println(name);
    }
}
public class Folder extends Directory {

    private final List<Directory> dirs = new ArrayList<>();
    private final Integer level;

    public Folder(String name, int level) {
        super(name);
        this.level = level;
    }

    @Override
    public void show() {
        System.out.println(name);
        if (level == null) {
            return;
        }
        for (Directory dir : dirs) {
            for (int i = 0; i < level; i++) {
                dir.show();
            }
        }
    }

    public void addDir(Directory dir){
        dirs.add(dir);
    }

    public void removeDir(Directory dir){
        dirs.remove(dir);
    }

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

Compare transparent mode with secure mode:

  • Transparent mode clients do not need to distinguish between branch and leaf nodes, which violates the principle of interface isolation. Leaf nodes inherit methods that should not be inherited
  • The security mode can obtain the hierarchy of branch nodes, which violates the dependency inversion principle. When calling from the client, it is necessary to distinguish between branch and leaf nodes
  • In essence, the combination mode ignores the differences of levels to achieve the purpose of simplification. The transparent mode is ignored in the abstract root node, and the security mode is judged in the tree node. There is no difference between them, but the different forms of the idea of combination mode. It reminds me of the previous exposition of "0" in the programmer's mathematics. 0 is either none or a special kind of "0"

Source application

JDK HashMap:

Node < K, V > [] tab attribute in HashMap. Its node is a node

transient Node<K,V>[] table;

Open source framework Mybatis:

Mybatis parses the SQL in each Mapping file and designs a top-level interface SqlNode. Each Node in xml will be parsed into a SqlNode object and finally spliced into a complete SQL

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

Personal experience

  • The combination mode simplifies the difficulty of controlling complex hierarchical systems
  • Using composite patterns makes the overall design more abstract

Tags: Java Design Pattern

Posted on Wed, 22 Sep 2021 22:19:02 -0400 by __greg