1、组合模式(Composite):
组合模式是为了解决整体和部分的一致对待的问题而产生的,要求这个整体与部分有一致的行为或操作,部分和整体都继承于一个公共的抽象类(公共操作),这样外部使用他们的时候是一致的 ,不管是对于整体还是部分使用一个方法即可遍历整体中所有的部分。上面说的可能有一些难懂,我们举一个例子。
有一家北京的公司在北京有自己的总部,还有旗下的很多个部门,这家北京的公司发展的很好,它在上海和杭州等地都有自己的分支公司,同样这些在其他地方的分公司旗下也有很多个部门,如果分支公司发展的好,同样也会在自己去开分公司,那么北京的总部在管理的时候只需要管理自己总部的部门和分公司,而不用去管理分公司的部门,因为分公司会用总部的管理方法去管理自己的部门和分公司。
A公司旗下有两个子公司 S1和S2,A公司还有四个部门(A1~A4),S1自己也有3个部门(S11 ~ S13)。A管理S1 ~ A4的方法与S1管理S11 ~ S13的方法相同。
2、代码
#include#include #include 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_vecComp; public: Composite(string name):Component(name){} ~Composite() { vector ::iterator ite = m_vecComp.begin(); while(ite != m_vecComp.end()) { if(*ite != NULL) { cout<<"delete"<<(*ite)->GetName()< :: 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 :: iterator ite ; for(ite = m_vecComp.begin(); ite != m_vecComp.end(); ite++ ) { cout<<(*ite)->GetName()< Add(pNode1); pNode0->Add(pNode2); pNode0->Add(pNode3); pNode0->Add(pNode4); pNode0->Print(); cout<<"---------------------------"< Add(pNode31); pNode3->Add(pNode32); pNode3->Add(pNode33); pNode3->Add(pNode34); pNode0->Print(); cout<<"---------------------------"< Print(); cout<<"---------------------------"< Remove(pNode34); pNode3->Print(); cout<<"---------------------------"< 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<GetChild(2)->GetName()< Add(pNode31); pNode3->Add(pNode32); pNode3->Add(pNode33); pNode3->Add(pNode34); pNode3->Operation(); cout< GetChild(1)->GetName()< 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



