1 Overview
Composite Pattern refers to the grouping of a class of objects with common abstractions into a tree structure to represent the part-whole relationship.
2 Combination mode
Often we encounter objects with the same behavior and hierarchical structure between them.In this case, the combination mode can make the system highly cohesive and less coupled.By grouping classes into a tree structure, callers can treat individual objects and the overall structure in a uniform way, ignoring differences between the individual and the whole.Implementing a combination pattern generally requires:
- Define an interface/abstract class and define the common behavior of objects, including methods for maintaining hierarchies between objects.
- Define the entity of the object and implement the methods in the interface/abstract class.
- All entities are grouped together in a tree structure to form a whole.
3 Cases
Take an example.Employees in all companies are actually members of the same family with similar attributes and behaviors. At the same time, there is a hierarchical structure among employees, which is a good way to represent the relationship between employees with a combination model:
public class Test { public static void main(String[] args) { // Building hierarchies Director director = new Director("Polly"); Manager frontendManager = new Manager("Lilei"); Manager backendManager = new Manager("Hanmeimei"); Engineer jsEngineer = new Engineer("Lily"); Engineer ueDesigner = new Engineer("Lucy"); Engineer javaEngineer = new Engineer("Jim"); Engineer dbAdmin = new Engineer("Kate"); director.addChild(frontendManager); director.addChild(backendManager); frontendManager.addChild(jsEngineer); frontendManager.addChild(ueDesigner); backendManager.addChild(javaEngineer); backendManager.addChild(dbAdmin); // Treat as a whole as a single object director.work(); } } // Public methods for Employee are defined, and methods for adding/deleting nodes are defined public interface Employee<T extends Employee> { String getName(); Collection<T> getChildren() throws OperationNotSupportedException; void addChild(T employee) throws OperationNotSupportedException; void removeChild(T employee) throws OperationNotSupportedException; void work(); } public class Director implements Employee<Manager> { private String name; private Collection<Manager> children = new ArrayList<>(); Director(String name) { this.name = name; }; [@Override](https://my.oschina.net/u/1162528) public String getName() { return name; } [@Override](https://my.oschina.net/u/1162528) public Collection getChildren() { return children; } [@Override](https://my.oschina.net/u/1162528) public void addChild(Manager employee) { children.add(employee); } [@Override](https://my.oschina.net/u/1162528) public void removeChild(Manager employee) { children.remove(employee); } // Loop-call method for child nodes [@Override](https://my.oschina.net/u/1162528) public void work() { System.out.println("Director " + name + " gives command to his subordinate..."); for (Employee child : children) { child.work(); } } } public class Manager implements Employee<Engineer> { private String name; private Collection<Engineer> children = new ArrayList<>(); Manager(String name) { this.name = name; }; @Override public String getName() { return name; } @Override public Collection getChildren() { return children; } @Override public void addChild(Engineer employee) { children.add(employee); } @Override public void removeChild(Engineer employee) { children.remove(employee); } // Loop-call method for child nodes @Override public void work() { System.out.println("Manager " + name + " gives command to his subordinates..."); for (Employee child : children) { child.work(); } } } public class Engineer implements Employee { private String name; Engineer(String name) { this.name = name; }; @Override public String getName() { return name; } @Override public Collection getChildren() throws OperationNotSupportedException { throw new OperationNotSupportedException("No child under engineer."); } @Override public void addChild(Employee employee) throws OperationNotSupportedException { throw new OperationNotSupportedException("Can not add child for engineer."); } @Override public void removeChild(Employee employee) throws OperationNotSupportedException { throw new OperationNotSupportedException("Can not remove child for engineer."); } @Override public void work() { System.out.println("Engineer " + name + " is coding..."); } }
Output:
Director Polly gives command to his subordinate... Manager Lilei gives command to his subordinates... Engineer Lily is coding... Engineer Lucy is coding... Manager Hanmeimei gives command to his subordinates... Engineer Jim is coding... Engineer Kate is coding...
Using the combination mode, we can operate on the whole and the individual objects with consistent behavior, which significantly reduces the complexity of the system.At the same time, the tree structure is easy to expand for future maintenance.
java.awt.Container uses the combination mode, and between components is a tree structure, and Container is the root node of all components:
public class Container extends Component { private java.util.List<Component> component = new ArrayList<>(); // add component protected void add(Component comp, Object constraints, int index) { ... //index == -1 means add to the end. if (index == -1) { component.add(comp); } else { component.add(index, comp); } comp.parent = this; comp.setGraphicsConfiguration(thisGC); ... } // Remove Components public void remove(int index) { synchronized (getTreeLock()) { ... component.remove(index); comp.setGraphicsConfiguration(null); ... } } // Call the updateGraphicsData method and the updateGraphicsData method of the child node boolean updateGraphicsData(GraphicsConfiguration gc) { boolean ret = super.updateGraphicsData(gc); for (Component comp : component) { if (comp != null) { ret |= comp.updateGraphicsData(gc); } } return ret; } ... }
4 Summary
When there is a hierarchical relationship between objects, you can consider using the combination mode to unify the single object and the combined object to reduce the system complexity.