组合模式是结构型模式中的一种,其组织类似与“树”。使用组合模式可以将整体与部分一视同仁的对待,这样忽略了组合对象与单个对象之间的不同。在处理整体与部分间的层次结构的时候也应该考虑使用组合模式的使用。
组合模式(Composite),将对象组合成树型结构以表示’部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
1.模式适用性
- 想表示对象的部分-整体层次结构时
- 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象时
2.模式结构
(1)Component:为组合的对象申明接口,在适当的情况下实现接口的默认行为。并且声明用于管理和访问Component子部件的接口(add,delete,getChild等)。
(2)Leaf:表示叶子节点对象,这样的节点对象无法添加子节点。
(3)Composite:枝节点,用于存储子部件,并且实现其本身相关的接口行为。
3.实现
有两种组合模式的实现方式:1.透明方式 2.安全方式。
1.透明方式:于Component中声明所有用来管理子对象的方法,包括Add,Remove等。实现Component接口的所有族类都具备了Add和Remove。这样的好处就是叶节点对于外界是没有区别的,他们具备完全一致的行为接口。但问题也是很明显,因为Leaf类本身不具备Add,Remove方法的功能,所以实现它是没有意义的。
2.安全方式:在Component接口中不去生命Add和Remove方法,那么子类Lead也就不需要去实现它,而是在Composite生命所有用来管理子类对象的方法,但这样做由于节点之间存在Add,Remove这样的管理方法之间的差异,需要客户端自行判断。
下面使用透明模式实现一个例子:
#include <iostream>
#include <string>
#include <list>
using namespace std;
class Component
{
public:
string name;
Component(string s) : name(s){}
virtual ~Component() {}
// defualt do nothing
virtual void Add(Component *c){}
virtual void Remove(Component *c) {}
virtual void Display(int depth) {};
};
class Leaf : public Component
{
public:
Leaf(string s) : Component(s) {}
void Display(int depth)
{
cout << string(depth, '-') << name << endl;
}
};
class Composite : public Component
{
private:
list<Component*> child;
public:
Composite(string s) : Component(s) {}
void Display(int depth)
{
cout << string(depth, '-') << name << endl;
list<Component*>::iterator it;
for(it = child.begin(); it != child.end(); ++it)
(*it)->Display(depth + 2);
}
void Add(Component *c)
{
child.push_back(c);
}
void Remove(Component *c)
{
child.remove(c);
}
};
int main()
{
Leaf *leafA = new Leaf("Leaf A");
Leaf *leafB = new Leaf("Leaf B");
Leaf *leafXA = new Leaf("Leaf XA");
Leaf *leafXB = new Leaf("Leaf XB");
Leaf *leafXYA = new Leaf("Leaf XYA");
Leaf *leafXYB = new Leaf("Leaf XYB");
Leaf *leafC = new Leaf("Leaf C");
Leaf *leafD = new Leaf("Leaf D");
Composite root("root");
root.Add(leafA);
root.Add(leafB);
Composite *comp = new Composite("Composite X");
comp->Add(leafXA);
comp->Add(leafXB);
root.Add(comp);
Composite *comp2 = new Composite("Composite XY");
comp2->Add(leafXYA);
comp2->Add(leafXYB);
comp->Add(comp2);
root.Add(leafC);
root.Add(leafD);
root.Remove(leafD);
root.Display(1);
delete leafA;
delete leafB;
delete leafXA;
delete leafXB;
delete leafXYA;
delete leafXYB;
delete leafC;
delete leafD;
delete comp;
delete comp2;
return 0;
}
4.总结
组合模式解决整体与部分统一对待的问题,能用到的场景是很广泛。例如我们要编写一个命令行工具,这个命令行工具是一个树形组织的,那么我们就可以使用组合模式。这样不仅可以方便的组合我们的命令结构,也便于届时添加和修改新的命令。上面的C++实现方法中有一个不好的地方就是需要手动删除创建的节点,我们可以考虑使用在Composite的析构函数中来实现删除节点,那么我们只要删除“根”节点,其子节点都可以随之释放。