目标:让用户遍历你的对象而无法窥视你存储对象的方式。如何创建对象的超集合。
迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而不暴露其内部的表示。迭代器模式把在元素之间游走的责任交给迭代器,而不是聚合对象。
迭代器类图:
组合模式:允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。
组合模式类图:

在开发中,可能要递归构建树状的组合结构,Composite模式则提供了很好的解决方案。
Component想相当于MenuComponent,Leaf相当MenuItem,Composite相当于Menu。
HeadFirst中菜单组合模式的C++实现:
Component.h头文件
#ifndef _COMPONENT_H_
#define _COMPONENT_H_
#include<string>
using namespace std;
class MenuComponent
{
public:
MenuComponent();
virtual ~MenuComponent();
//下面三个方法针对Menu
virtual void add(MenuComponent *menuCom);
virtual void remove(MenuComponent *menuCom);
virtual MenuComponent *getChild(int i);
//以下方法针对MenuItem
virtual string getName()=0;
virtual string getDescription()=0;
virtual double getPrice()=0;
virtual bool isVegetarian()=0;
virtual void print()=0;//同时被Menu和MenuItem实现
};
class Waitress
{
public:
Waitress(MenuComponent *allMenus);
~Waitress();
void printMenu();
protected:
private:
MenuComponent *allMenus;
};
#endif
Component.CPP
#include"Component.h"
MenuComponent::MenuComponent()
{
}
MenuComponent::~MenuComponent()
{
}
void MenuComponent::add(MenuComponent *menuCom)
{
}
void MenuComponent::remove(MenuComponent *menuCom)
{
}
MenuComponent *MenuComponent::getChild(int i)
{
return 0;
}
Waitress::Waitress(MenuComponent *allMenus)
{
this->allMenus=allMenus;
}
Waitress::~Waitress()
{
}
void Waitress::printMenu()
{
allMenus->print();
}
Composite.h
#ifndef _COMPOSITE_H_
#define _COMPOSITE_H_
#include"Component.h"
#include<string>
#include<vector>
#include<iostream>
using namespace std;
class Menu:public MenuComponent
{
public:
Menu(string name,string description);
~Menu();
void add(MenuComponent *menuCom);
void remove(MenuComponent *menuCom);
MenuComponent *getChild(int i);
string getName();
string getDescription();
double getPrice(); //这两个方法对于Menu无意义
bool isVegetarian();
void print();
protected:
private:
string name;
string description;
vector<MenuComponent *> menuVec;
};
#endif
Composite.CPP
#include "Composite.h"
Menu::Menu(string name, string description)
{
this->name=name;
this->description=description;
}
Menu::~Menu()
{
}
void Menu::add(MenuComponent *menuCom)
{
menuVec.push_back(menuCom);
}
void Menu::remove(MenuComponent *menuCom)
{
vector<MenuComponent *>::const_iterator const_it=menuVec.begin();
for(;const_it!=menuVec.end();const_it++)
{
if((*const_it)==menuCom)
menuVec.erase(const_it);
break;
}
// menuVec.erase(&menuCom);
}
MenuComponent * Menu::getChild(int i)
{
return menuVec[i];
}
string Menu::getName()
{
return name;
}
string Menu::getDescription()
{
return description;
}
double Menu::getPrice()
{
return 0;
}
bool Menu::isVegetarian()
{
return false;
}
void Menu::print()
{
cout<<endl<<getName()<<","<<getDescription()<<"---------"<<endl;
//让菜单不仅打印出本身的信息,也打印出菜单内所有组件的信息:其他菜单,菜单项
vector<MenuComponent *>::iterator it=menuVec.begin();
for(;it!=menuVec.end();it++)
{
(*it)->print(); //菜单和菜单项都实现了print()方法,相当于一个递归的过程
}
}
#ifndef _LEAF_H_
#define _LEAF_H_
#include"Component.h"
#include<string>
#include<iostream>
using namespace std;
class MenuItem:public MenuComponent
{
public:
MenuItem(string name,string description,bool vegetarian,double price);
~MenuItem();
string getName();
string getDescription();
double getPrice();
bool isVegetarian();
void print();
protected:
private:
string name;
string description;
bool vegetarian;
double price;
};
#endif
Leaf.CPP
#include "Leaf.h"
MenuItem::MenuItem(string name,string description,bool vegetarian,double price)
{
this->name=name;
this->description=description;
this->vegetarian=vegetarian;
this->price=price;
}
MenuItem::~MenuItem()
{
}
string MenuItem::getName()
{
return name;
}
string MenuItem::getDescription()
{
return description;
}
bool MenuItem::isVegetarian()
{
return vegetarian;
}
double MenuItem::getPrice()
{
return price;
}
void MenuItem::print()
{
cout<<" "<<getName();
if(isVegetarian())
cout<<" (v)";
cout<<","<<getPrice()<<" --"<<getDescription()<<endl;
}
main.CPP
//main.cpp
#include "Component.h"
#include "Composite.h"
#include "Leaf.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
//开始创建菜单
MenuComponent * pancakeHouseMenu=new Menu("PANCANK HOUSE MENU","Breakfast");
MenuComponent * dinnerMenu=new Menu("DINER MENU","Lunch");
MenuComponent * cafeMenu=new Menu("CAFE MENU","Dinner");
MenuComponent * dessertMenu=new Menu("DESSERT MENU","Dessert of course!");
MenuComponent *allMenus=new Menu("ALL MENUS","All Menus Combined");
//加入菜单到顶层菜单
allMenus->add(pancakeHouseMenu);
allMenus->add(dinnerMenu);
allMenus->add(cafeMenu);
//加入菜单项MenuItem
pancakeHouseMenu->add(new MenuItem("Pancak","pancak with milk",true,4.42));
dinnerMenu->add(new MenuItem("Pasta0","Spaghetti with Marinara Sauce and a slice of sourdough bread",true,3.89));
dinnerMenu->add(new MenuItem("Pasta1","Spaghetti with Marinara Sauce and a slice of sourdough bread",false,1.29));
Waitress waitress(allMenus);
waitress.printMenu();
return 0;
}