This is the 20th day of my participation in the November Gwen Challenge. Check out the details: The last Gwen Challenge 2021

Today we are going to study the composite pattern of structural design pattern. The application scenario of composite pattern is relatively special, requiring data to be represented as a tree structure, which leads to the composite pattern is not so common in actual project development.

An overview of the

Composite Design Pattern: The Composite Design Pattern organizes a group of objects into a tree structure to represent a partial-whole hierarchy. Composition allows clients to unify the processing logic of individual objects and composite objects.

The combination mode is generally used to describe the relationship between whole and part, and it organizes objects into a tree structure. The top node is called the root node. The root node can contain branch nodes and leaf nodes, and the branch node can also contain branch nodes and leaf nodes.

In fact, root nodes and branch nodes are essentially the same data type and can be used as containers. Leaf nodes and branch nodes do not belong to the same semantic type. In the composite pattern, however, the branch and leaf nodes are treated as belonging to the same data type (defined with a unified interface), allowing them to behave consistently.

When to use:

  • When your application structure has a tree-like hierarchy, such as file system, view tree, organizational structure, etc
  • When you want to manipulate individual objects and composite objects made up of them in a uniform way.

UML class diagram:

Role Composition:

  1. Abstract root node(Component) : Defines common methods and properties for objects at all levels of the system. Some default behaviors and properties can be predefined.
  2. The branch node(Composite) : Defines the behavior of branch nodes, stores child nodes, and combines branch nodes and leaf nodes to form a tree structure.
  3. A leaf node(Leaf) : the Leaf node object, which has no branches under it and is the smallest unit of system-level traversal.

Generic code

Abstract the root node component.java

public abstract class Component {

    protected String name;

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

    public abstract void otherMethod(a);

    public abstract void addChild(Component component);

    public abstract void removeChild(Component component);

    public abstract Component getChild(int index);

}
Copy the code

The branch node comp. Java

public class Composite extends Component {
    private List<Component> mLists = new ArrayList<>();

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

    @Override
    public void otherMethod(a) {
        System.out.println("name: " + name);
        if(mLists ! =null && mLists.size() > 0) {
            for(Component component : mLists) { component.otherMethod(); }}}@Override
    public void addChild(Component component) {
        mLists.add(component);
    }

    @Override
    public void removeChild(Component component) {
        mLists.remove(component);
    }

    @Override
    public Component getChild(int index) {
        returnmLists.get(index); }}Copy the code

The Leaf node leaf.java

public class Leaf extends Component {
    public Leaf(String name) {
        super(name);
    }

    @Override
    public void otherMethod(a) {
        System.out.println("name: " + name);

    }

    @Override
    public void addChild(Component component) {
        throw new UnsupportedOperationException("Leaf node has no children");
    }

    @Override
    public void removeChild(Component component) {
        throw new UnsupportedOperationException("Leaf node has no children");
    }

    @Override
    public Component getChild(int index) {
        throw new UnsupportedOperationException("Leaf node has no children"); }}Copy the code

The Client Client. Java

public class Client {

    private static Component constructTree(a) {
        // Construct a root node
        Component root = new Composite("Root");

        // Construct a branch node
        Component branchA = new Composite("Branch node branchA");
        Component branchB = new Composite("Branch node branchB");

        // Construct the leaf node
        Component leafA = new Leaf("Leaf node leafA");
        Component leafB = new Leaf("Leaf node LeafB");

        // Add the leaf node to the branch node
        branchA.addChild(leafA);
        branchB.addChild(leafB);

        // Add branch node to root node
        root.addChild(branchA);
        root.addChild(branchB);

        return root;
    }

    public static void main(String[] args) { Component component = constructTree(); component.otherMethod(); }}Copy the code

Results:

Name: Root node Root name: branchA name: leaf node leafA name: branchB name: leaf node LeafB

Combined pattern classification

The generic code above is actually one form of composite pattern: transparent composite pattern, but there is another form of composite pattern: secure composite pattern.

Transparent composition mode

In the transparent composition pattern, all the methods used to manage member objects are declared in the abstract root role, such as the addChild(), removeChild(), and getChild() methods declared in the Component example. This has the benefit of ensuring that all Component classes have the same interface. Transparent composition patterns are also the standard form of composition patterns.

The disadvantage of the transparent composite pattern is that it is not secure, because leaf objects and container objects are essentially different. Leaf objects cannot have next-level objects, that is, they cannot contain member objects, so it makes no sense to provide addChild(), removeChild(), and so on. This does not go wrong at compile time. However, it is possible to make an error if you call these methods at run time.

Security combination mode

In the secure Composite pattern, no methods for managing member objects are declared in the abstract artifact role. Instead, these methods are declared and implemented in the branch node Composite class. The downside of the secure composition pattern is that it is not transparent because the leaf and container components have different methods, and the methods used to manage the member objects in the container component are not defined in the abstract component class, so the client cannot be completely targeted at abstract programming and must treat the leaf and container components differently.

conclusion

The design idea of composite pattern is not so much a design pattern as an abstraction of data structure and algorithm for business scenarios. Among them, the data can be represented as a tree data structure, and the business needs can be realized by recursive traversal algorithm in the tree.

Disadvantages of composite mode:

  1. The design is more complex, and the client needs to spend more time sorting out the hierarchical relationships between classes.
  2. It is not easy to restrict components in containers;
  3. It is not easy to add new functions to components by inheritance.