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