为什么需要Composite设计模式?
如果客户代码过多地依赖于对象容器复杂的内部实现结构,对象容器内部实现结构(而非抽象接口)的变化将引起客户端的频繁变化,带来了代码的维护性、扩展性等弊端。
什么是Composite设计模式?
常常有一些组件在内部具有特定的数据结构,如果让客户程序依赖这些特定的数据结构,将极大地破坏组件的复用。这时候,将这些特定数据结构封装在内部,在外部提供统一的接口,来实现与特定数据结构无关的访问,是一种行之有效的解决方案。
composite模式将特定的数据结构封装在内部,使得客户端可以无差别的访问对象,而不必关心对象内部复杂的实现结构。
Composite设计模式特点
Composite模式采用树形结构来实现普遍存在的对象容器,从而将“一对多”的关系转化为“一对一”的关系,使得客户代码可以一致地(复用)处理对象和对象容器,无需关系处理的是单个对象,还是组合的对象容器。
将对象组合成属性结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性(稳定)。
将客户代码与复杂的对象容器结构解耦是Composite的核心思想,解耦之后,客户代码将与存粹的抽象接口-----而非对象容器的内部实现结构----发生依赖,从而更能应对变化。
类图
蓝色部分固定不变,红色虚线可能变化;客户端程序关联稳定的虚接口component;leaf和composite继承实现了component接口;同时,composite聚合component(composite中有component的成员变量);
Code
//对外提供的统一接口
/***************虚接口***************/
class Component
{
public:
virtual void process() = 0;
virtual ~Component(){}
};
/***************虚接口***************/
//内部复杂数据结构
/*******************************************
通过组合多态对象,将复杂结构实现隐藏在内部,根据客
户端传入对象不同,实现多态调用。
对外提供统一的Component接口
*******************************************/
class Composite : public Component{//树节点
string name;
list<Component*> elements;//多态对象---既可以存储树节点也可以存储子节点
public:
Composite(const string & s) : name(s) {}
void add(Component* element) {
elements.push_back(element);
}
void remove(Component* element){
elements.remove(element);
}
void process(){
//1. process current node
/**************根据e(多态对象)的不同调用不同的process函数********************/
//2. process leaf nodes
for (auto &e : elements)//多态递归调用
e->process(); //(既可以调用Composite的process也可以调用Leaf的process)
/**************根据e(多态对象)的不同调用不同的process函数********************/
}
};
//叶子节点
class Leaf : public Component{
string name;
public:
Leaf(string s) : name(s) {}
void process(){
//process current node
}
};
//客户端程序
/*************客户程序*************/
void Invoke(Component & c){//多态
//...
c.process();
//...
}
/*************客户程序*************/
int main()
{
Composite root("root");
Composite treeNode1("treeNode1");
Composite treeNode2("treeNode2");
Composite treeNode3("treeNode3");
Composite treeNode4("treeNode4");
Leaf leat1("left1");
Leaf leat2("left2");
root.add(&treeNode1);
treeNode1.add(&treeNode2);
treeNode2.add(&leaf1);
root.add(&treeNode3);
treeNode3.add(&treeNode4);
treeNode4.add(&leaf2);
Invoke(root);//无差别访问
Invoke(leaf2);//无差别访问
Invoke(treeNode3)//无差别访问
/***************************
客户代码不用了解实现细节,通
过递归多态将将内部实现细节隐
藏起来。客户端不必了解内部复
杂结构。
****************************/
}
适用性
以下情况下适用Composite模式:
1.你想表示对象的部分-整体层次结构
2.你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
例子
1.
2.