概述
组合模式有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
生活中的例子
组合模式将对象组合成树形结构以表示"部分-整体"的层次结构。让用户一致地使用单个对象和组合对象。虽然例子抽象一些,但是算术表 达式确实是组合的例子。算术表达式包括操作数、操作符和另一个操作数。操作数可以是数字,也可以是另一个表达式。这样,2+3和(2+3)+(4*6)都 是合法的表达式。(来自http://blog.163.com/renjianqin_1984/blog/static/1328821542010720104922316/)
在上面的图中,Component是组合和个体的基类,单个对象成了Leaf,而组合对象就是Composite,他们同时具有父类的操作。因此在客户看来他们是一致的。这样的话我们可以在Composite下再可以添加Composite对象或者Leaf对象,如此递归成了树形结构。
再来个例子(来自大话设计模式)
/*
有一家公司,总公司在北京,在上海有其在华东地区的分公司,然后在南京和杭州分别有各自的办事处。这里每个地方无论是总部还是分部都会有相同的部门设置,所以可以用Composite模式解决。
/*
#include<iostream> #include<string> #include<vector> using namespace std; class Company { protected: string cname; public: Company(string name):cname(name) { } virtual void Add(Company *c)=0;//增加 virtual void Remove(Company *c)=0;//删除 virtual void Display(int depth)=0;//显示 virtual void LineOfDuty()=0;//职责 }; //具体公司 class ConcreteCompany:public Company { private: vector<Company*> children; public: ConcreteCompany(string name):Company(name) { } void Add(Company *c) { children.push_back(c); } void Remove(Company *c) { children.erase(&c); } void Display(int depth) { string s(depth,'-'); cout<<s<<cname<<endl; vector<Company*>::iterator iter; for(iter=children.begin();iter!=children.end();iter++) { (*iter)->Display(depth+2); } } void LineOfDuty() { vector<Company*>::iterator iter; for(iter=children.begin();iter!=children.end();++iter) { (*iter)->LineOfDuty(); } } }; //人事部 class HRDepartment:public Company { private: vector<Company*> children; public: HRDepartment(string name):Company(name) { } void Add(Company *c) { children.push_back(c); } void Remove(Company *c) { children.erase(&c); } void Display(int depth) { string s(depth,'-'); cout<<s<<cname<<endl; } void LineOfDuty() { cout<<cname<<"\t员工招聘培训管理"<<endl; } }; //财务部 class FinanceDepartment:public Company { private: vector<Company*> children; public: FinanceDepartment(string name):Company(name) { } void Add(Company *c) { children.push_back(c); } void Remove(Company *c) { children.erase(&c); } void Display(int depth) { string s(depth,'-'); cout<<s<<cname<<endl; } void LineOfDuty() { cout<<cname<<"\t公司财务收支管理"<<endl; } }; int main() { ConcreteCompany *c=new ConcreteCompany("北京总公司"); c->Add(new HRDepartment("总公司人力资源部")); c->Add(new FinanceDepartment("总公司财务管理部")); ConcreteCompany *c1=new ConcreteCompany("上海华东分公司"); c1->Add(new HRDepartment("华东分公司人力资源部")); c1->Add(new FinanceDepartment("华东分公司财务部")); c->Add(c1); ConcreteCompany *c2=new ConcreteCompany("南京办事处"); c1->Add(c2); c2->Add(new HRDepartment("南京办事处人力资源部")); c2->Add(new FinanceDepartment("南京办事处财务部")); ConcreteCompany *c3=new ConcreteCompany("杭州办事处"); c1->Add(c3); c3->Add(new HRDepartment("杭州办事处人力资源部")); c3->Add(new FinanceDepartment("杭州办事处财务部")); cout<<"结构图:"<<endl; c->Display(1); cout<<endl; cout<<"职责:"<<endl; c->LineOfDuty(); return 0; }
运行结果:
这就是一个树形结构,子节点都可以跟父节点一样拥有相同的职能,但是他们所处的层次却是清晰地分开了,这就是Composite模式的好处。
注:组合模式一种继承关系,派生类中含有包含基类指针的容器。
组合模式和其他相关模式
1)装饰模式(Decorator模式)经常与Composite模式一起使用。当装饰和组合一起使用时,它们
通常有一个公共的父类。因此装饰必须支持具有 Add、Remove和GetChild 操作的Component接口。
2)Flyweight模式让你共享组件,但不再能引用他们的父部件。
3)(迭代器模式)Itertor可用来遍历Composite。
4)(观察者模式)Visitor将本来应该分布在Composite和L e a f类中的操作和行为局部化。