UML类图(仅供参考)如下:
组合模式解决的问题:
将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性,比如QT桌面应用开发框架中的控件
源码
#include <iostream>
#include <vector>
// Component抽象基类,相当于所有图形界面控件的公共父类一样
class CComponent
{
public:
virtual ~CComponent() {}
// 纯虚函数,只提供接口,没有默认的实现
virtual void Operation() = 0;
// 虚函数,提供接口,有默认的实现就是什么都不做
virtual void Add(CComponent*) {}
virtual void Remove(CComponent*) {}
virtual CComponent* GetChild(int index)
{
return nullptr;
}
protected:
CComponent() {}
};
// 相当于最基本的控件,比如Button、Edit这样的
class CLeaf :public CComponent
{
public:
// 每个控件都有自己的特殊功能
virtual void Operation()
{
std::cout << "CLeaf::Operation" << std::endl;
}
};
// 相当于一个对话框,上面还可以有很多控件在上面
class CComposite :public CComponent
{
public:
CComposite()
{
pChildren = new std::vector<CComponent *>();
}
~CComposite()
{
for (auto &var : *pChildren)
{
if (nullptr != var)
{
// 注意,这里的控件有可能被添加到多个父控件里
// 但是只能释放一遍(这里有可能释放了很多遍,所以一个控件只能有一个父控件)
// 建议这里的Add、Remove、GetChild方法都用类引用作为参数,这样就避免了上面的问题
// 而且也不用释放内存
delete var;
var = nullptr;
}
}
delete pChildren;
}
virtual void Operation()
{
std::cout << "CComposite::Operation" << std::endl;
}
// 添加一个子控件
virtual void Add(CComponent* com)
{
std::cout << "CComposite::Add" << std::endl;
pChildren->push_back(com);
}
// 移除一个子控件
virtual void Remove(CComponent* com)
{
std::cout << "CComposite::Remove" << std::endl;
auto var = std::find(pChildren->begin(), pChildren->end(), com);
if (pChildren->end() != var)
{
pChildren->erase(var);
}
}
// 获取一个子控件
virtual CComponent* GetChild(int index)
{
std::cout << "CComposite::GetChild" << std::endl;
return nullptr;
}
protected:
// 相当于所有子控件
std::vector<CComponent *> *pChildren;
};
// 测试
int main()
{
// 不管是叶子Leaf还是Composite对象pRoot、pCom都实现了Operation接口,所以可以一致对待,直接调用Operation()
// 体现了“使得用户对单个对象和组合对象的使用具有一致性”
CComposite* pRoot = new CComposite();
// 组合对象添加叶子节点
pRoot->Add(new CLeaf());
// 这里的叶子再添加叶子是没有意义的。
// 由于叶子与组合对象继承了相同的接口,所以语法上是对的,实际上什么也没做(继承自基类Component的Add方法)。
// 叶子节点只实现了Operation方法,其他Add、Remove、GetChild都继承自基类,没有实际意义。
CLeaf* pLeaf1 = new CLeaf();
CLeaf* pLeaf2 = new CLeaf();
pLeaf1->Add(pLeaf2);
pLeaf1->Remove(pLeaf2);
// 执行叶子Operation操作
pLeaf1->Operation();
// 组合对象实现了基类Component的所有接口,所以可以做各种操作(Add、Remove、GetChild、Operation)。
CComposite* pCom = new CComposite();
// 组合对象添加叶子节点
pCom->Add(pLeaf1);
// 组合对象添加叶子节点
pCom->Add(pLeaf2);
// 执行组合对象Operation操作
pCom->Operation();
// 组合对象添加组合对象
pRoot->Add(pCom);
// 执行组合对象Operation操作
pRoot->Operation();
pCom->Remove(pLeaf1);
return 0;
}
好处
1、高层模块调用简单。
2、节点自由增加。