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