说明:本文仅供学习交流,转载请标明出处,欢迎转载!
组合模式(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设计模式》