说明:本文仅供学习交流,转载请标明出处,欢迎转载!
组合模式(Composite)也叫部分-整体模式,是一种非常实用的设计模式,当我们发现需求中系统体现的是整体与局部的层次关系,并且用户希望将组合对象和单个对象一致性对待,这个时候“组合模式”的作用可以得到淋漓尽致地发挥了。
接触过Linux的人都知道Linux的文件系统采用的一种树状的层次结构,在Linux系统中,目录和普通文件都被系统视为文件,而目录内又可以包含普通文件,这样Linux的文件系统就是以这种递归的方式定义。如果我们想描述这样的数据结构,可以考虑采用组合模式。
组合模式的定义:将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
从上面的定义我们可以得出组合模式的两大特点:
1.从模式结构本身来看:模式本身体现的是一种整体与部分的层次结构关系;
2.从用户的角度(客户端)分析:整体(分支结点)与部分(叶子结点)具有相同的接口,被形态上没有差别。
组合模式的结构
本图来自《大话设计模式》
举例
下图是一种组合模式的举例:
C++实现代码(针对以上面的举例)
#include<iostream> #include<string> #include<list> using namespace std; class Component//抽象类,用户通过该接口来访问其子部件 { protected: string name; public: Component(){} Component(string str):name(str){}; virtual void Add(Component*)=0;//增加子部件 virtual void Remove(Component*)=0;//删除子部件 virtual void Display(int depth)=0;//遍历结点,depth表示结点的深度 }; class Leaf:public Component { public: Leaf(string name):Component(name){}//调用基类的构造函数初始化派生类的基类部分 void Add(Component* c) { cout<<"不能向叶子结点添加部件!"<<endl; } void Remove(Component* c) { cout<<"不能从叶子结点删除部件!"<<endl; } void Display(int depth) { cout<<string(depth,'-')<<name<<endl; } }; class Composite:public Component//添加分支结点(即非叶子结点) { private: list<Component*> child;//孩子 public: Composite(){}//基类Component调用其默认的构造函数 Composite(string name):Component(name){} void Add(Component *c) { child.push_back(c); } void Remove(Component *c) { child.remove(c); } void Display(int depth) { cout<<string(depth,'-')<<name<<endl; list<Component*>::iterator iter=child.begin(); while(iter!=child.end()) { (*iter)->Display(depth+1);//递归遍历 iter++; } } }; int main() { Composite root("root"); /****添加root的孩子结点pA****/ Leaf *pA=new Leaf("Leaf A"); root.Add(pA); /****添加root的孩子结点pB***/ Leaf *pB=new Leaf("Leaf B");//添加root的孩子pB root.Add(pB); /****添加root的分支结点comp***/ Composite *comp1=new Composite("Composite X"); Leaf *pXA=new Leaf("Leaf XA"); Leaf *pXB=new Leaf("Leaf XB"); root.Add(comp1); /***添加comp1的分支结点comp2****/ Composite *comp2=new Composite("Composite XY"); Leaf *pXYA=new Leaf("Leaf XYA"); Leaf *pXYB=new Leaf("Leaf XYB"); comp2->Add(pXYA); comp2->Add(pXYB); comp1->Add(comp2); /***添加root的孩子结点pC和pD****/ Leaf *pC=new Leaf("Leaf C"); Leaf *pD=new Leaf("Leaf D"); root.Add(pC); root.Add(pD); cout<<"显示当前树的结果:"<<endl; root.Display(1); /****删除root的孩子结点pD***/ cout<<"显示删除结点D后的结果:"<<endl; root.Remove(pD);//注意,只是从树中删除了,并没有从堆中删除 root.Display(1); /***释放所申请的堆内存空间,C++的麻烦就在此呀,哈哈***/ delete pA; delete pB; delete comp1; delete pC; delete pD; delete pXA; delete pXB; delete comp2; delete pXYA; delete pXYB; return 0; }
测试结果
参考资料:
[1]《大话设计模式》
[2]《设计模式之禅》
[3]《HeadFirst设计模式》