design_pattern_iterator

This post implements Iterator Pattern in <Head First Design Patterns>. 


Take traversal-of-a-collection functionality out of the collection and promote it to "full object status". This simplifies the collection, allows many traversals to be active simultaneously, and decouples collection algorithms from collection data structures.

"Every 'container-like' class must have an iterator." It may seem like a violation of encapsulation for a Stack class to allow its users to access its contents directly, but John Lakos' argument is that the designer of a class inevitably leaves something out. Later, when users need additional functionality, if an iterator was originally provided, they can add functionality with "open for extension, closed for modification". Without an iterator, their only recourse is to invasively customize production code. Below, the orginal Stack class did not include an equality operator,but it did include an iterator. As a result, the equality operator could be readily retrofitted.

  1. Design an "iterator" class for the "container" class
  2. Add a createIterator() member to the container class
  3. Clients ask the container object to create an iterator object
  4. Clients use the first(), isDone(), next(), andcurrentItem() protocol

First of all, we define Menu class

class MenuItem {
private:
    std::string name;
	std::string description;
	bool vegetarian;
	double price;

public:
    MenuItem(std::string name, std::string description, bool vegetarian, double price) {
		this->name = name;
		this->description = description;
		this->vegetarian = vegetarian;
		this->price = price;
	}

	virtual std::string getName() { return name; }
	virtual std::string getDescription() { return description; }
	virtual double getPrice() { return price; }
	virtual bool isVegetarian() { return vegetarian; }
	virtual void toString() {
		std::stringstream result (name.c_str());
		result << " $" << price << std::endl << description.c_str();
	}
};

class Menu {
public:
    virtual ~Menu() {}
	virtual Iterator<MenuItem>* createIterator() const = 0;
};

class PancakeHouseMenu : public Menu {
private:
    std::vector<MenuItem*> menuItems;

public:
    PancakeHouseMenu() {
		addItem("K&B's Pancake Breakfast",
			"Pancakes with scrambled eggs, and toast",
			true,
			2.99);

		addItem("Regular Pancake Breakfast",
			"Pancakes with fried eggs, sausage",
			false,
			2.99);

		addItem("Blueberry Pancakes",
			"Pancakes made with fresh blueberries",
			true,
			3.49);

		addItem("Waffles",
			"Waffles, with your choice of blueberries or strawberries",
			true,
			3.59);
	}

	virtual void addItem(std::string name, std::string description, bool vegetarian, double price) {
		MenuItem* menuItem = new MenuItem(name, description, vegetarian, price);
		menuItems.push_back(menuItem);
	}

	virtual std::vector<MenuItem*> getMenuItems() {
		return menuItems;
	}

	virtual Iterator<MenuItem>* createIterator() {
		return dynamic_cast<Iterator<MenuItem>*> (new PancakeHouseMenuIterator(menuItems));
	}

	virtual void toString() {
		std::cout << "Objectville Pancake House Menu" << std::endl;
	}

	// other menu methods here
};

class DinerMenu : public Menu {
private:
    static const int MAX_ITEMS = 6;
	int numberOfItems;
	MenuItem** menuItems;

public:
    DinerMenu() : numberOfItems(0) {
		menuItems = new MenuItem*[MAX_ITEMS + 1];	// added one additional entry;
		for (int i = 0; i <= MAX_ITEMS; i++)		// to hold a null (0) value
			menuItems[i] = 0;						// so hasNext() will work

		addItem("Vegetarian BLT",
			"(Fakin') Bacon with lettuce & tomato on whole wheat", true, 2.99);
		addItem("BLT",
			"Bacon with lettuce & tomato on whole wheat", false, 2.99);
		addItem("Soup of the day",
			"Soup of the day, with a side of potato salad", false, 3.29);
		addItem("Hotdog",
			"A hot dog, with saurkraut, relish, onions, topped with cheese",
			false, 3.05);
		addItem("Steamed Veggies and Brown Rice",
			"Steamed vegetables over brown rice", true, 3.99);
		addItem("Pasta",
			"Spaghetti with Marinara Sauce, and a slice of sourdough bread",
			true, 3.89);
	}

	virtual void addItem(std::string name, std::string description, bool vegetarian, double price) {
		MenuItem* menuItem = new MenuItem(name, description, vegetarian, price);
		if (numberOfItems >= MAX_ITEMS) {
			std::cerr << "Sorry, menu is full!  Can't add item to menu" << std::endl;
		} else {
			menuItems[numberOfItems] = menuItem;
			numberOfItems = numberOfItems + 1;
		}
	}

	virtual MenuItem** getMenuItems() {
		return menuItems;
	}

	virtual Iterator<MenuItem>* createIterator() {
		return dynamic_cast<Iterator<MenuItem>*>(new DinerMenuIterator(menuItems));
	}
	// other menu methods here
};


Then , we define iterator class

#include<./menu.hpp>

template <class T>
class Iterator {
	public: virtual bool hasNext() = 0;
	public: virtual T* next() = 0;
};

class PancakeHouseMenuIterator : public Iterator<MenuItem> {
private:
    std::vector<MenuItem*> items;
	int position;

public:
    PancakeHouseMenuIterator(std::vector<MenuItem*> items) : position(0) {
		this->items = items;
	}

	virtual MenuItem* next() {
	    // return current item, move position to next
		MenuItem* menuItem = items[position];
		position = position + 1;
		return menuItem;
	}

	virtual bool hasNext() {
		if (position >= static_cast<int>(items.size())) {
			return false;
		} else {
			return true;
		}
	}
};

class DinerMenuIterator : public Iterator<MenuItem> {
private:
    MenuItem** items;
	int position;

	DinerMenuIterator(MenuItem** items) : position(0) {
		this->items = items;
	}

	virtual MenuItem* next() {
		MenuItem* menuItem = items[position];
		position = position + 1;
		return menuItem;
	}

	virtual bool hasNext() {
		if (items[position] == 0) {
			return false;
		} else {
			return true;
		}
	}
};
The waitress class

#include<./menu.hpp>
#include<./iterator.hpp>
#include<vector>

class Waitress {
	PancakeHouseMenu* pancakeHouseMenu;
	DinerMenu* dinerMenu;

public:
    Waitress(PancakeHouseMenu* pancakeHouseMenu, DinerMenu* dinerMenu) {
		this->pancakeHouseMenu = pancakeHouseMenu;
		this->dinerMenu = dinerMenu;
	}

	virtual void printMenu() {
		Iterator<MenuItem>* pancakeIterator = pancakeHouseMenu->createIterator();
		Iterator<MenuItem>* dinerIterator = dinerMenu->createIterator();

		std::cout << "MENU\n----\nBREAKFAST" << std::endl;
		printMenu(pancakeIterator);
		std::cout << "\nLUNCH" << std::endl;
		printMenu(dinerIterator);
	}

	virtual void printVegetarianMenu() {
		printVegetarianMenu(pancakeHouseMenu->createIterator());
		printVegetarianMenu(dinerMenu->createIterator());
	}

	virtual bool isItemVegetarian(std::string name) {
		Iterator<MenuItem>* breakfastIterator = pancakeHouseMenu->createIterator();
		if (isVegetarian(name, breakfastIterator)) {
			return true;
		}
		Iterator<MenuItem>* dinnerIterator = dinerMenu->createIterator();
		if (isVegetarian(name, dinnerIterator)) {
			return true;
		}
		return false;
	}

private:
    virtual void printMenu(Iterator<MenuItem>* iterator) {
		while (iterator->hasNext()) {
			MenuItem* menuItem = dynamic_cast<MenuItem*>(iterator->next());
			std::cout << menuItem->getName() << ", ";
			std::cout << menuItem->getPrice() << " -- ";
			std::cout << menuItem->getDescription() << std::endl;
		}
	}

	void printVegetarianMenu(Iterator<MenuItem>* iterator) {
		while (iterator->hasNext()) {
			MenuItem* menuItem = dynamic_cast<MenuItem*>(iterator->next());
			if (menuItem->isVegetarian()) {
				std::cout << menuItem->getName();
				std::cout << "\t\t" << menuItem->getPrice();
				std::cout << "\t" << menuItem->getDescription() << std::endl;
			}
		}
	}

	bool isVegetarian(std::string name, Iterator<MenuItem>* iterator) {
		while (iterator->hasNext()) {
			MenuItem* menuItem = dynamic_cast<MenuItem*>(iterator->next());
			if (menuItem->getName().compare(name) == 0) {
				if (menuItem->isVegetarian()) {
					return true;
				}
			}
		}
		return false;
	}
};
main function

#include <iostream>
#include <./menu.hpp>
#include <./iterator.hpp>
#include <./waitress.hpp>

int main()
{
    PancakeHouseMenu* pancakeHouseMenu = new PancakeHouseMenu();
    DinerMenu* dinerMenu = new DinerMenu();

	Waitress* waitress = new Waitress(pancakeHouseMenu, dinerMenu);

	waitress->printMenu();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值