Mastering the Composite Pattern: Tree Structures and Real‑World Examples
This article explains the Composite design pattern, detailing its definition, benefits, and implementation through JavaScript examples such as a startup command sequence and an employee‑department hierarchy, while highlighting key considerations, common pitfalls, and best practices for effective use.
Composite Pattern
Definition
The Composite pattern composes objects into tree structures to represent part‑whole hierarchies, allowing clients to treat individual objects and compositions uniformly.
Key terms include “part‑whole”, “leaf object”, and “composite object”. Understanding these concepts is essential.
Purpose
The pattern serves two main purposes:
Compose objects into a tree to depict part‑whole relationships.
Leverage polymorphism so that clients can use leaf and composite objects interchangeably.
Below is a simple JavaScript macro‑command example that simulates a computer startup sequence.
let runWeChat = {
run: function() {
console.log("wechat已经启动")
}
}
let runQQ = {
run: function() {
console.log("QQ已经启动")
}
}
let runChrome = {
run: function() {
console.log("Google Chrome已经启动")
}
}
let applicationCommand = function () {
return {
commandLists: [],
addCommand: function (command) {
this.commandLists.push(command)
},
run: function () {
this.commandLists.map((item, index) => {
item.run()
})
}
}
}
let ac = applicationCommand()
ac.addCommand(runWeChat)
ac.addCommand(runQQ)
ac.addCommand(runChrome)
ac.run()The tree traversal allows the composite’s run method to invoke each child’s run, so pressing the power button sequentially starts WeChat, QQ, and Chrome.
Because of polymorphism, users do not need to distinguish between leaf and composite objects when invoking run.
In real development this simplifies adding new commands: as long as an object provides a run method, it can be added without the client caring about its nature.
When a request reaches a leaf, it handles it; when it reaches a composite, the request is propagated to its children. A more complex tree is illustrated below.
Example: Employee‑Department Relationship
In a company each department is a composite; sub‑teams are also composites, and individual employees are leaves. The following JavaScript code models this hierarchy.
let leaderStaff = function (name, sex, apartment) {
this.name = name;
this.sex = sex;
this.apartment = apartment;
this.children = [];
}
leaderStaff.prototype.add = function (child) {
this.children.push(child)
}
leaderStaff.prototype.doCount = function () {
console.log("leader", this.name + "--" + this.sex + "--" + this.apartment)
this.children.map((child, index) => {
child.doCount()
})
}
let staff = function(name, sex, apartment) {
this.name = name;
this.sex = sex;
this.apartment = apartment;
}
staff.prototype.add = function() {
throw new Error("我还只是个孩子!!->_->")
}
staff.prototype.doCount = function () {
console.log("普通员工", this.name + "--" + this.sex + "--" + this.apartment)
}
let leaderStaff1 = new leaderStaff('大旺', '男', 'A')
let leaderStaff2 = new leaderStaff('大张', '男', 'B')
let leaderStaff3 = new leaderStaff('大李', '男', 'C')
let leaderStaff4 = new leaderStaff('大无', '女', 'D')
let staff5 = new staff('小马', '', '0')
let staff1 = new staff('小黑', '男', 'd')
let staff2 = new staff('小撒', '女', 'e')
let staff3 = new staff('小周', '女', 'f')
let staff4 = new staff('小郑', '男', 'g')
leaderStaff1.add(leaderStaff3);
leaderStaff1.add(leaderStaff2);
leaderStaff1.add(leaderStaff4);
leaderStaff1.add(staff1);
leaderStaff3.add(staff4);
leaderStaff3.add(staff3);
leaderStaff4.add(staff2);
leaderStaff1.doCount();The execution result (shown in the image) demonstrates the tree structure and the counting output.
Leaders (composites) have children; employees (leaves) do not. The example shows how adding new nodes does not require changing existing code, adhering to the Open‑Closed Principle.
Considerations
Composite is a HAS‑A relationship, not an IS‑A inheritance relationship.
Leaf and composite objects must share a common interface for consistent operations.
If an object belongs to multiple composites, the strict hierarchy breaks down, making the pattern unsuitable.
For large trees, performance can suffer; combining with the Chain of Responsibility pattern can limit traversal to the first capable handler.
Conclusion
The Composite pattern provides a convenient way to build tree‑like object structures and treat them uniformly, but its drawbacks—such as runtime‑only distinction between leaf and composite—must be kept in mind.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
MaoDou Frontend Team
Open-source, innovative, collaborative, win‑win – sharing frontend tech and shaping its future.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
