组合模式(Composite Pattern)和适配器模式(Adapter Pattern)都是结构型设计模式,它们解决的问题不同,应用场景也不一样。下面我来对比一下这两种模式的区别:
1. 目标和用途
组合模式(Composite Pattern)
- 目标:处理树形结构的对象,将“部分”与“整体”进行统一处理。
- 用途:组合模式的主要目的是让你能够将单个对象和对象集合(例如树结构)统一处理。它解决的是部分-整体的关系,使得客户端可以像操作单个对象一样操作一组对象。
适配器模式(Adapter Pattern)
- 目标:将一个类的接口转换为客户端所期望的接口,适配不同的接口。
- 用途:适配器模式的目的是解决接口不兼容的问题,让不同的接口可以协同工作。它提供了一个适配层,使得原本不兼容的类可以互相调用。
2. 结构
组合模式
组合模式的核心思想是通过递归地将对象组成树形结构,部分和整体有相同的接口。无论是一个单独的对象(叶子节点)还是一个包含多个子对象的组合(树枝节点),都实现相同的接口。这样,客户端就可以统一对待单一对象和复合对象。
示例结构:
- Component(组件接口):定义统一的操作。
- Leaf(叶子节点):实现单一对象。
- Composite(树枝节点):包含多个子组件,可以包含Leaf或者其他Composite对象。
适配器模式
适配器模式通过引入一个适配器类来实现接口转换。它将原本不兼容的接口转换成客户端期望的接口。
示例结构:
- Target(目标接口):客户端期望的接口。
- Adapter(适配器类):将源接口转化为目标接口。
- Adaptee(源类):需要被适配的类。
3. 使用场景
组合模式
适用于需要表示树形结构的情况,比如:
- 组织架构(员工、经理、部门等)。
- 文件系统(文件夹和文件)。
- UI组件(按钮、窗口、面板等)。
例如:在公司管理系统中,经理可以管理下属,员工和经理都实现统一的Employee接口。无论是一个普通员工还是一个管理着其他员工的经理,都可以通过相同的方法来处理。
适配器模式
适用于接口不兼容的情况,尤其是需要使两个本来不兼容的类能够合作时。
- 例如:将一个旧系统的接口适配到新的系统接口中。
- 将第三方库的接口适配到你自己的项目中。
比如你有一个第三方库提供的类,它的方法名称或参数不同于你自己系统的要求,这时你可以通过适配器模式来转换它们的接口,使它们能够顺利协作。
4. 实现区别
组合模式实现
组合模式强调统一的接口,并通过递归构建树形结构。它允许客户端通过统一接口操作复杂的层次结构,无论是叶子节点还是复合节点。客户端代码不需要关心每个节点是单一对象还是一个组合,均通过统一接口处理。
适配器模式实现
适配器模式主要是通过引入一个适配器类来转换接口。适配器类会将源类的接口转换成目标接口,以便兼容客户端的需求。
5. 总结对比
特征 | ||
目标 | 统一处理单个对象和对象的组合(树形结构)。 | 将不兼容的接口适配成客户端所期望的接口。 |
主要用途 | 处理部分和整体的关系(树形结构)。 | 解决不同接口不兼容的问题。 |
结构 | Component 接口, Leaf (叶子节点), Composite (树枝节点)。 | Target (目标接口), Adapter (适配器), Adaptee (被适配类)。 |
应用场景 | 组织架构、文件系统、UI组件等树形结构。 | 接口不兼容时,需转换接口以便合作。 |
设计目标 | 使客户端能够统一处理单个对象和组合对象。 | 使得不兼容的类可以协同工作。 |
6. 简单示例
组合模式(员工管理例子)
class Employee {
public:virtual void showDetails() = 0;
};class Developer : public Employee {
public:void showDetails() override {std::cout << "Developer details..." << std::endl;}
};class Manager : public Employee {
private:std::vector<Employee*> subordinates;
public:void addSubordinate(Employee* employee) {subordinates.push_back(employee);}void showDetails() override {std::cout << "Manager details..." << std::endl;for (auto& subordinate : subordinates) {subordinate->showDetails();}}
};
适配器模式(旧接口适配到新接口)
class Target {
public:virtual void request() = 0;
};class Adaptee {
public:void specificRequest() {std::cout << "Specific request!" << std::endl;}
};class Adapter : public Target {
private:Adaptee* adaptee;
public:Adapter(Adaptee* adaptee) : adaptee(adaptee) {}void request() override {adaptee->specificRequest(); // 转发请求}
};