1.概述
组合模式又叫部分整体模式属于结构型模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。
2.结构
- 组件(Component):定义了组合中所有对象的通用接口,可以是抽象类或接口。它声明了用于访问和管理子组件的方法,包括添加、删除、获取子组件等。
- 叶子节点(Leaf):表示组合中的叶子节点对象,叶子节点没有子节点。它实现了组件接口的方法,但通常不包含子组件。
- 复合节点(Composite):表示组合中的复合对象,复合节点可以包含子节点,可以是叶子节点,也可以是其他复合节点。它实现了组件接口的方法,包括管理子组件的方法。
- 客户端(Client):通过组件接口与组合结构进行交互,客户端不需要区分叶子节点和复合节点,可以一致地对待整体和部分。
3.实现
3.1 实例类比
以电脑文件系统为例,其中有两种类型的文件:文本文件和文件夹。文本文件是叶子节点,文件夹是组合节点,可以包含其他文件。
类体如下:
3.2 具体实现
#include <iostream>
#include <string>
#include<vector>
using namespace std;
/**
* Component抽象类,表示目录条目(文件+文件夹)的抽象类
**/
class Component {
public:
virtual string getName() = 0; //获取文件名
virtual int getSize() = 0; //获取文件大小
//添加文件夹或文件
virtual Component* add(Component* entry) = 0;
//显示指定目录下的所有信息
virtual void printList(string prefix) {};
};
/**
* File类 表示文件
**/
class File :public Component {
private:
string name_; //文件名
int size; //文件大小
public:
File(string name, int size) {
this->name_ = name;
this->size = size;
}
string getName() {
return name_;
}
int getSize() {
return size;
}
Component* add(Component* entry) {
return nullptr;
}
void printList(string prefix) {
cout << prefix + "/" << name_ << endl;
}
};
/**
* Directory表示文件夹
**/
class Directory :public Component {
//文件的名字
private:
string name_;
//文件夹与文件的集合
vector<Component*> directory;
public:
//构造函数
Directory(string name) {
this->name_ = name;
}
//获取文件名称
string getName() {
return this->name_;
}
int getSize() {
int size = 0;
//遍历或者去文件大小
for (auto it : directory) {
size += it->getSize();
}
return size;
}
Component* add(Component* entry) {
directory.push_back(entry);
return this;
}
//显示目录
void printList(string prefix) {
cout << prefix << "/" << name_ << endl;
for (auto it : directory) {
it->printList(prefix + "/" + name_);
}
}
};
int main()
{
//根节点
Directory *rootDir = new Directory("root");
//树枝节点
Directory *binDir = new Directory("bin");
//向bin目录中添加叶子节点
binDir->add(new File("test1", 1024));
binDir->add(new File("test2", 2048));
Directory *nginxlDir = new Directory("ngnix");
Directory *confDir = new Directory("conf");
nginxlDir->add(confDir);
confDir->add(new File("nginx.conf", 30));
rootDir->add(binDir);
rootDir->add(nginxlDir);
rootDir->printList("");
return 0;
}
3.3运行结果
4.状态设计模式优缺点
优点:
- 可以将对象组合成树形结构,表示整体-部分的层次关系。
- 可以统一处理单个对象和对象组合,简化了客户端的代码逻辑,提高了系统的可复用性。
- 可以遵循开闭原则,扩展性高,增加新的节点类型时不需要修改原有代码。
缺点
对于功能差异较大的类, 提供公共接口或许会有困难。 在特定情况下, 你需要过度一般化组件接口, 使其变得令人难以理解。
5 应用场景
- 当需要表示一个对象整体与部分的层次结构时,可以使用组合模式来实现树形结构。例如,文件系统中的文件与文件夹、组织机构中的部门与员工、商品分类中的类别与商品等。
- 当需要统一处理单个对象和对象组合时,可以使用组合模式来实现多态性。例如,图形界面中的简单控件与容器控件、菜单系统中的菜单项与子菜单、报表系统中的单元格与表格等。
- 当需要将对象的创建和使用分离时,可以使用组合模式来实现依赖注入。例如,Spring框架中的Bean对象与BeanFactory对象、测试框架中的测试用例与测试套件等。