1. 设计模式原理说明
组合模式(Composite Pattern) 是一种结构型设计模式,它允许你将对象组合成树形结构来表示“部分-整体”的层次关系。组合模式使得用户对单个对象和组合对象的使用具有一致性。这意味着无论处理的是单一对象还是复合对象,都可以使用相同的接口进行操作。
主要角色
- Component(组件):定义了树中每个对象的接口,可以是叶子节点或容器节点。
- Leaf(叶子节点):表示树中的末端节点,没有子节点,实现
Component
接口的具体行为。 - Composite(容器节点):表示树中的分支节点,可以包含一个或多个子节点,实现了
Component
接口的行为,并负责管理子节点的添加、删除等操作。 - Client(客户端):通过
Component
接口与所有对象交互,无需关心对象是叶子节点还是容器节点。
2. UML 类图及解释
UML 类图
+-----------------+ +-----------------+
| Component | | Leaf |
|-----------------| |-----------------|
| + operation(): void| | + operation(): void|
+-----------------+ +-----------------+^ ^| || |v v
+-----------------+
| Composite |
|-----------------|
| - children: List<Component> |
| + add(child: Component): void|
| + remove(child: Component): void|
| + getChild(index: int): Component|
| + operation(): void |
+-----------------+
类图解释
- Component:定义了树中每个对象的接口,可以是叶子节点或容器节点。客户端通过这个接口与所有对象交互。
- Leaf:表示树中的末端节点,没有子节点,实现
Component
接口的具体行为。 - Composite:表示树中的分支节点,可以包含一个或多个子节点,实现了
Component
接口的行为,并负责管理子节点的添加、删除等操作。 - Client:通过
Component
接口与所有对象交互,无需关心对象是叶子节点还是容器节点。
3. 代码案例及逻辑详解
Java 代码案例
// 组件接口
interface Component {void operation();
}// 叶子节点
class Leaf implements Component {@Overridepublic void operation() {System.out.println("Leaf operation");}
}// 容器节点
class Composite implements Component {private List<Component> children = new ArrayList<>();public void add(Component component) {children.add(component);}public void remove(Component component) {children.remove(component);}public Component getChild(int index) {return children.get(index);}@Overridepublic void operation() {for (Component child : children) {child.operation();}}
}// 客户端
public class Client {public static void main(String[] args) {Composite root = new Composite();Composite branch = new Composite();Leaf leaf1 = new Leaf();Leaf leaf2 = new Leaf();branch.add(leaf1);branch.add(leaf2);root.add(branch);root.operation();// 输出:// Leaf operation// Leaf operation}
}
C++ 代码案例
#include <iostream>
#include <vector>// 组件接口
class Component {
public:virtual void operation() = 0;virtual ~Component() {}
};// 叶子节点
class Leaf : public Component {
public:void operation() override {std::cout << "Leaf operation" << std::endl;}
};// 容器节点
class Composite : public Component {
private:std::vector<Component*> children;public:void add(Component* component) {children.push_back(component);}void remove(Component* component) {children.erase(std::remove(children.begin(), children.end(), component), children.end());}Component* getChild(int index) {return children[index];}void operation() override {for (Component* child : children) {child->operation();}}~Composite() {for (Component* child : children) {delete child;}}
};// 客户端
int main() {Composite* root = new Composite();Composite* branch = new Composite();Leaf* leaf1 = new Leaf();Leaf* leaf2 = new Leaf();branch->add(leaf1);branch->add(leaf2);root->add(branch);root->operation();// 输出:// Leaf operation// Leaf operationdelete root;return 0;
}
Python 代码案例
from abc import ABC, abstractmethod
from typing import List# 组件接口
class Component(ABC):@abstractmethoddef operation(self):pass# 叶子节点
class Leaf(Component):def operation(self):print("Leaf operation")# 容器节点
class Composite(Component):def __init__(self):self.children: List[Component] = []def add(self, component: Component):self.children.append(component)def remove(self, component: Component):self.children.remove(component)def get_child(self, index: int) -> Component:return self.children[index]def operation(self):for child in self.children:child.operation()# 客户端
if __name__ == "__main__":root = Composite()branch = Composite()leaf1 = Leaf()leaf2 = Leaf()branch.add(leaf1)branch.add(leaf2)root.add(branch)root.operation()# 输出:# Leaf operation# Leaf operation
Go 代码案例
package mainimport "fmt"// 组件接口
type Component interface {Operation()
}// 叶子节点
type Leaf struct{}func (l *Leaf) Operation() {fmt.Println("Leaf operation")
}// 容器节点
type Composite struct {children []Component
}func (c *Composite) Add(child Component) {c.children = append(c.children, child)
}func (c *Composite) Remove(child Component) {for i, ch := range c.children {if ch == child {c.children = append(c.children[:i], c.children[i+1:]...)break}}
}func (c *Composite) GetChild(index int) Component {return c.children[index]
}func (c *Composite) Operation() {for _, child := range c.children {child.Operation()}
}// 客户端
func main() {root := &Composite{}branch := &Composite{}leaf1 := &Leaf{}leaf2 := &Leaf{}branch.Add(leaf1)branch.Add(leaf2)root.Add(branch)root.Operation()// 输出:// Leaf operation// Leaf operation
}
4. 总结
组合模式 是一种结构型设计模式,它允许你将对象组合成树形结构来表示“部分-整体”的层次关系。组合模式使得用户对单个对象和组合对象的使用具有一致性,从而提高了系统的灵活性和可扩展性。
主要优点
- 一致性:用户可以通过相同的接口操作单个对象和组合对象,使得客户端代码更加简洁和一致。
- 灵活性:组合模式使得树形结构的构建更加灵活,可以动态地添加和删除节点。
- 易于扩展:新增节点类型时,只需实现
Component
接口即可,无需修改现有代码。
主要缺点
- 增加了系统的复杂性:组合模式引入了更多的类和接口,增加了系统的复杂性。
- 客户端需要谨慎处理空指针:如果客户端代码不小心访问了空指针,可能会导致运行时错误。
适用场景
- 当需要表示部分-整体层次结构时。
- 当希望用户可以忽略组合对象与单个对象的不同,统一使用组合结构中的所有对象。
- 当系统中存在复杂的树形结构,需要频繁地添加、删除节点时。