[设计模式]Composite组合模式

问题

在开发中,我们经常可能要递归构建树状的组合结构在我们软件系统开发中,会遇到简单对象与复杂对象一起使用的情况,就好比刚刚说的文件目录一样,可以包含文件和文件夹,文件夹下面也可以包含文件和文件夹。但是由于简单对象和复杂对象在功能使用上还是有一定的区别的,可能会造成客户端调用时较为麻烦。这时候就需要将简单对象和复杂对象统一一致对待。然而组合模式也就是解决这一麻烦的。

composite组合模式

将对象组合成树形结构以表示“部分-整体”的层次结构。它使得客户对单个对象和组合对象的使用具有一致性。

 [设计模式]Composite组合模式_第1张图片

  • component部件为组合中的对象声明接口,声明了类共有接口的缺省行为。声明一个接口函数用于访问和管理Component的子部件
  • composite组合定义有枝节点行为,用来存储子部件,在component接口中实现与子部件有关的操作,Add,Remove等
  • leaf叶子:在组合模式中表示叶节点对象,叶节点没有子节点

Component组件是为解决组件之间的递归组合提供了解决的办法,它主要分为两个派生类,其中的Leaf是叶子结点,也就是不含有子组件的结点,而Composite是含有子组件的类.举一个例子来说明这个模式,在UI的设计中,最基本的控件是诸如Button,Edit这样的控件,相当于是这里的Leaf组件,而比较复杂的控件比如List则可也看做是由这些基本的组件组合起来的控件,相当于这里的Composite,它们之间有一些行为含义是相同的,比如在控件上作一个点击,移动操作等等的,这些都可以定义为抽象基类中的接口虚函数,由各个派生类去实现之,这些都会有的行为就是这里的Operation函数,而添加,删除等进行组件组合的操作只有非叶子结点才可能有,所以虚拟基类中只是提供接口而且默认的实现是什么都不做.

composite组合模式比较容易理解,想到composite组合模式就应该想到树形结构图。组合体内这些对象都有共同接口,当组合体一个对象的方法被调用执行时,composite将遍历(iterator)整个树形结构,寻找同样包含这个方法的对象并调用执行。可以用牵一动百来形容。所以composite组合模式使用到了Iterator模式,和Chain Of Responsibility模式类似。

[设计模式]Composite组合模式_第2张图片

[设计模式]Composite组合模式_第3张图片

抽象构件角色:这是一个抽象角色,它给参加组合的对象定义了公共的接口和行为,在透明式的组合模式中,包含了对所有子对象的管理。但是在安全式的组合模式中,这里不定义管理子对象的方法,而是由树枝构件定义给出。
树叶构件:树叶构件意味着没有下级对象,定义了参加组合对象的原始行为。
树枝构件:代表有下级对象(树枝或树叶都有可能),给出管理其子类的对象。

  • 使用场景:1、部分——整体的环境。例如树型菜单,文件管理2、用户希望对简单对象与复杂对象拥有一致的操作时
  • 优点:1、组合模式使得处理简单对象和复杂对象有一致的操作,无需关心处理的简单对象还是复杂对象2、更简单快捷的加入新的节点
  • 缺点:使得设计复杂,难于理清层次

小demo

composite.h

/********************************************************************
	created:	2006/07/20
	filename: 	Composite.h
	author:		李创
                http://www.cppblog.com/converse/

	purpose:	Composite模式的演示代码
*********************************************************************/

#ifndef COMPOSITE_H
#define COMPOSITE_H
#include 
#include 
using namespace std;
// 组合中的抽象基类
class Component
{
private:
        string m_strName;
public:
	Component(string paramName){m_strName=paramName;}
	virtual ~Component(){}
    
	// 纯虚函数,只提供接口,没有默认的实现
	virtual void Operation() = 0;

	// 虚函数,提供接口,有默认的实现就是什么都不做
        virtual void Add(Component* pChild){}//添加一个子部件
        virtual void Remove(Component* pChild){}//删除一个子部件
        virtual Component* GetChild(int nIndex){return NULL;}//获取子部件的指针
};

// 派生自Component,是其中的叶子组件的基类
class Leaf  : public Component
{
public:
        Leaf(string strParam):Component(strParam){}
	virtual ~Leaf(){}

	virtual void Operation();
};

// 派生自Component,是其中的含有子件的组件的基类
class Composite	: public Component
{
public:
        Composite(string strParam):Component(strParam){}
	virtual ~Composite();

	virtual void Operation();

	virtual void Add(Component* pChild);
	virtual void Remove(Component* pChild);
	virtual Component* GetChild(int nIndex);

private:
	// 采用list容器去保存子组件
	std::list	m_ListOfComponent;
};

#endif

composite.cpp

/********************************************************************
	created:	2006/07/20
	filename: 	Composite.cpp
	author:		李创
                http://www.cppblog.com/converse/

	purpose:	Composite模式的演示代码
*********************************************************************/

#include "Composite.h"
#include 
#include 
  
/*-------------------------------------------------------------------
	Leaf成员函数的实现
-------------------------------------------------------------------*/
void Leaf::Operation()
{
    static int a=0;
    a=a++;
    std::cout << "Operation by leaf\n"<::iterator iter1, iter2, temp;

	for (iter1  = m_ListOfComponent.begin(), iter2 = m_ListOfComponent.end();
		 iter1 != iter2;
		 )
	{
		temp = iter1;
		++iter1;
		delete (*temp);
	}
}

void Composite::Add(Component* pChild)
{
	m_ListOfComponent.push_back(pChild);
}

void Composite::Remove(Component* pChild)
{
	std::list::iterator iter;

	iter = find(m_ListOfComponent.begin(), m_ListOfComponent.end(), pChild);

	if (m_ListOfComponent.end() != iter)
	{
	    m_ListOfComponent.erase(iter);
	}
}

Component* Composite::GetChild(int nIndex)
{
	if (nIndex <= 0 || nIndex > m_ListOfComponent.size())
		return NULL;

	std::list::iterator iter1, iter2;
	int i;
	for (i = 1, iter1  = m_ListOfComponent.begin(), iter2 = m_ListOfComponent.end();
		iter1 != iter2;
		++iter1, ++i)
	{
		if (i == nIndex)
			break;
	}

	return *iter1;
}

void Composite::Operation()
{
	std::cout << "Operation by Composite\n";

	std::list::iterator iter1, iter2;

	for (iter1  = m_ListOfComponent.begin(), iter2 = m_ListOfComponent.end();
		iter1 != iter2;
		++iter1)
	{
		(*iter1)->Operation();
	}
}

main.cpp

#include "Composite.h"
#include  
int main()
{ 
	Component* pCom = new Composite("Compostie");
	pCom->Add(new Leaf("leaf1"));
	pCom->Add(new Leaf("leaf2"));

	pCom->Operation();
	pCom->GetChild(2)->Operation();
        delete pCom;

        Component* myCom = new Composite("myCompostie");
        myCom->Add(new Leaf("leaf3"));
        delete myCom;

	system("pause");
	return 0;
}
  • 使客户端调用简单,客户端可以一致的使用组合结构或单个对象,用户就不必关心自己处理的是单个对象还是整个组合结构,这就简化了客户端代码
  • 更容易在组合体内加入对象部件。客户端不必因为加入了新的对象部件二更改代码。

如何使用composite?

首先定义一个接口或抽象类,这是设计模式的通用方式,其他设计模式对接口内部定义限制不多,composite却有个规定,那就是要在接口内部定义一个用于访问和管理composite组合体对象们(或称部件component)。

与其他模式的关系

  • 在创建复杂组合树时使用建造者模式,因为这可使其构造步骤以递归的方式运行
  • 责任链模式通常和组合模式结合使用。在这种情况下,叶组件接收到请求后,可以将请求沿包含全体父组件的链一直传递至对象树的底部。
  • 可以使用迭代器模式来遍历组合树
  • 可以使用访问者模式对整个组合树执行操作
  • 可以使用享元模式实现组合树的共享叶节点以节省内存
  • 组合和装饰模式的结构图很相似,因为两者都依赖递归组合来组织无限数量的对象。装饰类似于组合,但其只有一个子组件。此外还有一个明显不同:装饰为被封装对象添加了额外的职责,组合仅对其子节点的结果进行了“求和”
  • 大量使用组合和装饰的设计通常可从对于原型模式的使用中获益。你可以通过该模式来复制复杂结构,而非从零开始重新构造。

你可能感兴趣的:(模式架构)