The of Java design pattern -- composite pattern

Posted by SwiftlyTilting on Mon, 29 Nov 2021 01:20:44 +0100

1. What is combination mode?

Compose objects into tree structures to represent part-whole hierarchies.Composite lets clients treat individual objects and compositions of objects uniformly.

Composite Pattern: combine objects into a tree structure to represent the "part whole" hierarchy, so that users can use single objects and composite objects consistently.

Speaking: used to process tree structured data.

2. Combination mode definition

① , Component abstract Component role

Define common methods and properties of objects participating in the composition, and you can define some default behaviors or properties.

② Leaf node

The leaf object, under which there are no other child nodes, is the smallest unit of traversal.

③ . Composite branch component

Branch object is used to combine branch nodes and leaf nodes to form a tree structure.

3. General code implementation of composite mode

/**
 * Abstraction of individual and whole
 */
public abstract class Component {
    // Shared by individuals and the whole
    public void doSomething(){
        // General business logic
        System.out.println("General business logic");
    }
}
/**
 * Branch node
 */
public class Composite extends Component{
    // Component container
    private ArrayList<Component> componentArrayList = new ArrayList<>();

    // Add a leaf node or branch node
    public void add(Component component){
        this.componentArrayList.add(component);
    }

    // Delete a leaf node or branch node
    public void remove(Component component){
        this.componentArrayList.remove(component);
    }

    // Get all leaf nodes and branch nodes under the branch
    public List<Component> getChildren(){
        return this.componentArrayList;
    }
}
/**
 * Leaf node
 */
public class Leaf extends Component {

    // Override parent method
    @Override
    public void doSomething() {
        // Leaf node logic
        System.out.println("Leaf node logic");
    }
}

Test:

public class ClientTest {

    public static void main(String[] args) {
        // Create a root node
        Composite root = new Composite();
        root.doSomething();
        // Create a branch component
        Composite branch = new Composite();
        // Create a leaf node
        Leaf leaf = new Leaf();

        // In series
        root.add(branch);
        branch.add(leaf);

        display(root);
    }

    // Pass through recursion
    public static void display(Composite root){
        for(Component c : root.getChildren()){
            if(c instanceof Leaf){ // Leaf node
                c.doSomething();
            }else{
                display((Composite) c);
            }
        }
    }
}

Here we give an example:

Suppose we are developing an OA system (office automation system). The company's organizational structure includes two data types: Department and employee. Among them, the Department can include sub departments and employees.

We hope to build the personnel structure diagram of the whole company (Department, sub department and employee affiliation) in memory, and provide an interface to calculate the salary cost of the Department (the salary and salary of all employees belonging to the Department).

/**
 * Abstract classes of department class and Employee class
 */
public abstract class HumanResource {
    protected long id;
    protected double salary;

    public HumanResource(long id){
        this.id = id;
    }

    public long getId(){
        return id;
    }

    public abstract double calculateSalary();

}
public class Department extends HumanResource{
    private List<HumanResource> subNodes = new ArrayList<>();

    public Department(long id){
        super(id);
    }

    @Override
    public double calculateSalary() {
        double totalSalary = 0d;
        for (HumanResource hr : subNodes){
            totalSalary += hr.calculateSalary();
        }
        this.salary = totalSalary;
        return totalSalary;
    }

    public void addSubNode(HumanResource humanResource){
        subNodes.add(humanResource);
    }
}
public class Employee extends HumanResource{
    public Employee(long id,double salary){
        super(id);
        this.salary = salary;
    }

    @Override
    public double calculateSalary() {
        return salary;
    }
}

Test:

public class PersonClientTest {
    private static final long ORGANIZATION_ROOT_ID = 1;

    public static void main(String[] args) {
        // Create head office
        Department root = new Department(ORGANIZATION_ROOT_ID);

        // Create sub department
        Department branch = new Department(2L);

        // Create employee
        Employee employee1 = new Employee(21L,2000);
        Employee employee2 = new Employee(22L,4000);

        root.addSubNode(branch);
        branch.addSubNode(employee1);
        branch.addSubNode(employee2);

        double v = root.calculateSalary();
        System.out.println(v);
    }

    private void buildOrganization(Department department){
        // Query the id of all subordinate departments in the database according to the Department id
        // List<Long> subDepartmentIds = departmentRepo.getSubDepartmentIds(department.getId());
        List<Long> subDepartmentIds = new ArrayList<>();

        for (Long subDepartmentId : subDepartmentIds){
            Department subDepartment = new Department(subDepartmentId);
            department.addSubNode(subDepartment);
            buildOrganization(subDepartment);
        }

        // Query all the IDs of the associated employees in the database according to the Department id
        // List<Long> employeeIds = employeeRepo.getDepartmentEmployeeIds(department.getId());
        List<Long> employeeIds = new ArrayList<>();
        for (Long employeeId : employeeIds){
            // Query the database according to employeeId to get salary
            // Assume 1000
            double salary = 1000d;
            department.addSubNode(new Employee(employeeId,salary));
        }


    }
}

4. Advantages of combined mode

① Simple high-level module call

All nodes in a tree mechanism are components. There is no difference between local and overall for the caller, that is, the high-level module does not have to care whether it is dealing with a single object or the whole composite structure, which simplifies the code of the high-level module.

② . nodes can be added freely

After using the combination mode, if you want to add a branch node or leaf node, it is easy to find its parent node. It is very easy to expand and conforms to the opening and closing principle, which is very beneficial to future maintenance.

5. Combined mode application scenario

As long as it is a tree structure, you can consider using a composite pattern.

① , maintenance and presentation of part - overall relationship scenarios, such as tree menu, file and folder management.

② A scenario in which some modules or functions can be separated from a whole

Topics: Java Design Pattern