定义
(GoF《设计模式》):将对象组合成树形结构以表示“部分整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
组成
① Component 是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component子部件。
② Leaf 在组合中表示叶子结点对象,叶子结点没有子结点。
③ Composite 定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加(add)和删除(remove)等。
适用性
以下情况下适用Composite模式:
1.你想表示对象的部分-整体层次结构
2.你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
例子
我们每天在公司上班,我们的公司其实就是一个树型结构的,最上边是总公司,总公司下面还有很多子公司, 而每个子公司有很很多部门。这样整个大公司就是一颗大树,每个子公司同时也是一颗小叔
首先是公司的抽象接口
// 公司抽象类 class Company{public : Company(std::string name) :m_name(name) { } virtual ~Company( ) { } virtual void Add(Company *pCompany) // 增加子公司 { } virtual void Show(int depth) = 0; // 显示部门protected : std::string m_name; // 显示公司名字};
其次是公司的实现
// 公司类 class ConcreteCompany : public Company{public : ConcreteCompany(std::string name) :Company(name) { } virtual ~ConcreteCompany( ){ }; // 虚析构函数 void Add(Company *company) // 添加子公司 { this->m_companyList.push_back(company); // 将子公司或者部门加入到公司的列表中 } void Show(int depth) // 显示公司部门 { for(int pos = 0; pos < depth; pos++) { std::cout <<"-"; } std::cout <<this->m_name <<std::endl; for(std::list<Company *>::iterator it = this->m_companyList.begin( ); it != this->m_companyList.end( ); ++it) { (*it)->Show(depth + 2); } }protected : std::list<Company *> m_companyList; // 下属公司列表};
接着是财务部门的实现
// 财务部门 class FinaceDepartment : public Company{public : FinaceDepartment(std::string name) :Company(name) { } virtual ~FinaceDepartment( ) { } void Show(int depth) // 显示公司部门 { for(int pos = 0; pos < depth; pos++) { std::cout <<"-"; } std::cout <<this->m_name <<std::endl; }};
然后是人力资源部门
// 人力部门 class HRDepartment : public Company{public : HRDepartment(std::string name) :Company(name) { } virtual ~HRDepartment( ){ }; // 虚析构函数 void Show(int depth) // 显示公司部门 { for(int pos = 0; pos < depth; pos++) { std::cout <<"-"; } std::cout <<this->m_name <<std::endl; }};
最后是客户端代码
int main(){ // 总公司 Company *root = new ConcreteCompany("总公司"); Company *rootHR = new HRDepartment("人力资源部"); Company *rootFI = new FinaceDepartment("财务部"); root->Add(rootHR); root->Add(rootFI); // 分公司A Company *left = new ConcreteCompany("分公司A"); Company *leftHR = new HRDepartment("分公司A人力资源部"); Company *leftFI = new FinaceDepartment("分公司A财务部"); left->Add(leftHR); left->Add(leftFI); root->Add(left); // 分公司B Company *right = new ConcreteCompany("分公司B"); Company *righHR = new HRDepartment("分公司B人力资源部"); Company *righFI = new FinaceDepartment("分公司B财务部"); right->Add(righHR); right->Add(righFI); root->Add(right); root->Show(0); return 0;}
总结
组合模式解耦了客户程序与复杂元素内部结构,从而使客户程序可以像处理简单元素一样来处理复杂元素。
如果你想要创建层次结构,并可以在其中以相同的方式对待所有元素,那么组合模式就是最理想的选择。本章使用了一个文件系统的例子来举例说明了组合模式的用途。在这个例子中,文件和目录都执行相同的接口,这是组合模式的关键。通过执行相同的接口,你就可以用相同的方式对待文件和目录,从而实现将文件或者目录储存为目录的子级元素。