C++常见设计模式之组合模式

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

Guess you like

Origin blog.csdn.net/scarificed/article/details/121341677