定义
组合模式允许将对象组合成树形结构来表现“整体/部分”层次结构。组合能够让客户以一致的方式处理个别对象以及对象组合。
要点
1.组合模式让我们能用树形方式创建对象的结构,树里面包含了组合以及个别对象。
2.组合模式允许客户对个别对象(叶节点)以及组合对象一视同仁。
3.组合结构内的任意对象称为组件,组件可以是组合,也可以是叶节点。
4.也节点和组合必须实现相同的接口。
类图
Component:组合中所有对象接口,不管是组合还是叶节点。
Leaf:叶节点,没有孩子。
Composite:组合,包含有一个或多个孩子(可以是叶节点,也可以是组合)。
示例
实现如下图所示菜单:
MunuComponent.h
#ifndef MENUCOMPONENT_H
#define MENUCOMPONENT_H
namespace menu
{
class MenuComponent
{
public:
class UnSupportedOperation{};
MenuComponent(){}
virtual ~MenuComponent(){}
virtual void addMenuItem(MenuComponent *m)
{
throw UnSupportedOperation();
}
virtual void print(int indent = 0) = 0;
};
}
#endif
MenuItem.h
#ifndef MENUITEM_H
#define MENUITEM_H
#include <iostream>
#include <string>
#include "MenuComponent.h"
namespace menu
{
using std::string;
using std::cout;
using std::endl;
// 菜单项 (叶节点)
class MenuItem: public MenuComponent
{
public:
MenuItem(string n, int p): name(n), price(p)
{}
~MenuItem(){}
void print(int indent)
{
for (int i = 0; i < indent; i++)
{
cout << " ";
}
cout << name << ":" << price << endl;
}
private:
string name;
int price;
};
}
#endif
Menu.h
#ifndef SUBMENU_H
#define SUBMENU_H
#include <iostream>
#include <string>
#include <vector>
#include "MenuComponent.h"
namespace menu
{
using std::string;
using std::cout;
using std::endl;
using std::vector;
// 菜单 (组合)
class Menu: public MenuComponent
{
public:
Menu(string n): name(n)
{}
~Menu()
{
// should free vector memory
}
void addMenuItem(MenuComponent *m)
{
menuVector.push_back(m);
}
void print(int indent)
{
for (int i=0; i<indent; i++)
{
cout << " ";
}
cout << name << "(Sub):" << endl;
vector<MenuComponent *>::const_iterator it = menuVector.begin();
while(it != menuVector.end())
{
(*it)->print(indent + 1);
it++;
}
}
private:
vector<MenuComponent *> menuVector;
string name;
};
}
#endif
main.cpp
#include "MenuItem.h"
#include "Menu.h"
using namespace menu;
int main()
{
MenuComponent *m = new Menu("Diner");
m->addMenuItem(new MenuItem("Meat", 12));
m->addMenuItem(new MenuItem("Fish", 10));
m->addMenuItem(new MenuItem("Steak", 9));
// 子菜单
MenuComponent *mm = new Menu("Dessert");
mm->addMenuItem(new MenuItem("Icecream", 9));
mm->addMenuItem(new MenuItem("Cookie", 3));
m->addMenuItem(mm);
m->print();
delete m;
delete mm;
return 0;
}
测试
测试结果如下图所示: