1、组合模式(Composite):
组合模式是为了解决整体和部分的一致对待的问题而产生的,要求这个整体与部分有一致的行为或操作,部分和整体都继承于一个公共的抽象类(公共操作),这样外部使用他们的时候是一致的 ,不管是对于整体还是部分使用一个方法即可遍历整体中所有的部分。上面说的可能有一些难懂,我们举一个例子。
有一家北京的公司在北京有自己的总部,还有旗下的很多个部门,这家北京的公司发展的很好,它在上海和杭州等地都有自己的分支公司,同样这些在其他地方的分公司旗下也有很多个部门,如果分支公司发展的好,同样也会在自己去开分公司,那么北京的总部在管理的时候只需要管理自己总部的部门和分公司,而不用去管理分公司的部门,因为分公司会用总部的管理方法去管理自己的部门和分公司。
A公司旗下有两个子公司 S1和S2,A公司还有四个部门(A1~A4),S1自己也有3个部门(S11 ~ S13)。A管理S1 ~ A4的方法与S1管理S11 ~ S13的方法相同。
2、代码
#include<iostream>
#include<string>
#include<vector>
using namespace std;
// 抽象的部件类描述将来所有部件共有的行为
class Component
{
protected:
string m_strCompname; //公司或者部门名称
public:
Component (string name):m_strCompname(name){
}
virtual ~Component(){
}
virtual void Operation() = 0;
virtual void Add(Component*) = 0;
virtual void Remove(Component*) = 0;
virtual Component* GetChild(int) = 0;
virtual string GetName()
{
return m_strCompname;
}
virtual void Print() = 0;
};
class Leaf :public Component
{
public:
Leaf(string name):Component(name){
}
void Operation()
{
cout<<"I am "<<m_strCompname<<endl;
}
void Add(Component* pComponent){
}
void Remove(Component* pComponent){
}
Component*GetChild(int index)
{
return NULL;
}
void Print(){
}
};
class Composite :public Component
{
private:
vector<Component*> m_vecComp;
public:
Composite(string name):Component(name){
}
~Composite()
{
vector<Component*>::iterator ite = m_vecComp.begin();
while(ite != m_vecComp.end())
{
if(*ite != NULL)
{
cout<<"delete"<<(*ite)->GetName()<<endl;
delete *ite;
*ite = NULL;
}
m_vecComp.erase(ite);
ite = m_vecComp.begin();
}
}
void Operation()
{
cout<<"I am "<<m_strCompname<<endl;
}
void Add(Component* pComponent)
{
m_vecComp.push_back(pComponent);
}
void Remove(Component* pComponent)
{
vector<Component*>:: iterator ite ;
for(ite = m_vecComp.begin(); ite != m_vecComp.end(); ite++ ){
if((*ite)->GetName() == pComponent->GetName())
{
if(*ite != NULL)
{
delete *ite;
*ite = NULL;
}
m_vecComp.erase(ite);
break;
}
}
}
Component*GetChild(int index)
{
if(index > m_vecComp.size())
{
return NULL;
}
return m_vecComp[index-1];
}
void Print()
{
vector<Component*>:: iterator ite ;
for(ite = m_vecComp.begin(); ite != m_vecComp.end(); ite++ )
{
cout<<(*ite)->GetName()<<endl;
}
}
};
int main()
{
Component * pNode0 = new Composite("北京总部");
Component * pNode1 = new Composite("北京总部人力资源部门");
Component * pNode2 = new Composite("杭州分支");
Component * pNode3 = new Composite("上海分支");
Component * pNode4 = new Composite("重庆分支");
pNode0->Add(pNode1);
pNode0->Add(pNode2);
pNode0->Add(pNode3);
pNode0->Add(pNode4);
pNode0->Print();
cout<<"---------------------------"<<endl;
Component * pNode31 = new Leaf("上海人力资源部门");
Component * pNode32 = new Leaf("上海采购部门");
Component * pNode33 = new Leaf("上海销售部门");
Component * pNode34 = new Leaf("上海质量监督部门");
pNode3->Add(pNode31);
pNode3->Add(pNode32);
pNode3->Add(pNode33);
pNode3->Add(pNode34);
pNode0->Print();
cout<<"---------------------------"<<endl;
pNode3->Print();
cout<<"---------------------------"<<endl;
//公司最近资金短缺 需要关闭上海质量监督部门
pNode3->Remove(pNode34);
pNode3->Print();
cout<<"---------------------------"<<endl;
if(pNode0 != NULL)
{
delete pNode0;
pNode0 = NULL;
}
return 0;
}
int main()
{
Component * pNode0 = new Composite("北京总部");
Component * pNode1 = new Composite("北京总部人力资源部门");
Component * pNode2 = new Composite("杭州分支");
Component * pNode3 = new Composite("上海分支");
Component * pNode4 = new Composite("重庆分支");
pNode0->Add(pNode1);
pNode0->Add(pNode2);
pNode0->Add(pNode3);
pNode0->Add(pNode4);
pNode0->Operation();
cout<<pNode0->GetChild(2)->GetName()<<endl; //北京总部旗下的第二个公司或者部门的名字
Component * pNode31 = new Leaf("上海人力资源部门");
Component * pNode32 = new Leaf("上海采购部门");
Component * pNode33 = new Leaf("上海销售部门");
Component * pNode34 = new Leaf("上海质量监督部门");
pNode3->Add(pNode31);
pNode3->Add(pNode32);
pNode3->Add(pNode33);
pNode3->Add(pNode34);
pNode3->Operation();
cout<<pNode3->GetChild(1)->GetName()<<endl; //上海分支旗下的第一个公司或者部门的名字
pNode3->GetChild(1)->GetChild(1); //Leaf 叶子节点 没有分支或者节点
pNode31->GetChild(1);
if(pNode0!=NULL)
{
delete pNode0;
pNode0 = NULL;
}
return 0;
}
3、实现要点:
1)Composite的关键之一在于一个抽象类,它既可以代表Leaf,又可以代表Composite;所以在实际实现时,应该最大化Component接口,Component类应为Leaf和Composite类尽可能多定义一些公共操作。Component类通常为这些操作提供缺省的实现,而Leaf和Composite子类可以对它们进行重定义;
2)Component是否应该实现一个Component列表,在上面的代码中,我是在Composite中维护的列表,由于在Leaf中,不可能存在子Composite,所以在Composite中维护了一个Component列表,这样就减少了内存的浪费;
3)内存的释放;由于存在树形结构,当父节点都被销毁时,所有的子节点也必须被销毁,所以,我是在析构函数中对维护的Component列表进行统一销毁,这样就可以免去客户端频繁销毁子节点的困扰;
4)由于在Component接口提供了最大化的接口定义,导致一些操作对于Leaf节点来说并不适用,比如:Leaf节点并不能进行Add和Remove操作,由于Composite模式屏蔽了部分与整体的区别,为了防止客户对Leaf进行非法的Add和Remove操作,所以,在实际开发过程中,进行Add和Remove操作时,需要进行对应的判断,判断当前节点是否为Composite。
5、何时使用组合模式?
当你发现需求中是体现部分与整体层次结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一的使用组合结构中的所有对象时,就应该考虑使用组合模式 。基本对象可以被组合成更复杂的组合对象,而这个组合对象又可以被组合,这样不断递归下去。客户代码中任何用到基本对象的地方都可以使用组合对象 ,用户不用关心到底是处理一个叶节点还是处理一个组合组件, 因为他们的处理方式都是相同的。
组合模式意图是通过整体与局部之间的关系,通过树形结构的形式进行组织复杂对象,屏蔽对象内部的细节,对外展现统一的方式来操作对象,是我们处理更复杂对象的一个手段和方式。
其中部分内容参考于:https://www.jb51.net/article/55878.htm