C++ 设计模式《外卖菜单展示》

👨‍🎓 模式名称:迭代器模式(Iterator)

👦 故事背景:

随着"小明万能校园平台"大获成功,美食外卖成为热门功能之一。每天成百上千的订单进出,小明打算给每个商家都做一个"外卖菜单展示"模块,供 App 客户端遍历显示菜单上的菜品。

但问题出现了......

🌀 没有使用迭代器模式的困扰

各个商家有自己"奇葩"的菜单数据结构:

  • 🧋 奶茶店:菜单是一个 std::vector

  • 🍱 便当店:菜单是一个 std::map<int, MealItem>

  • 🍢 烧烤摊:菜单是一个 std::list

小明展示菜单时,不得不硬写很多重复代码:

cpp 复制代码
void printMilkTeaMenu(std::vector<DrinkItem>& drinks) {
    for (auto& d : drinks) {
        std::cout << d.name << " - " << d.price << "\n";
    }
}

void printMealMenu(std::map<int, MealItem>& meals) {
    for (auto& [id, m] : meals) {
        std::cout << m.name << " - " << m.price << "\n";
    }
}

void printBBQMenu(std::list<BBQItem>& bbqs) {
    for (auto& b : bbqs) {
        std::cout << b.name << " - " << b.price << "\n";
    }
}

使用迭代器模式:为所有菜单提供统一遍历方式

🧠 关键目标:隐藏底层数据结构,实现统一遍历接口

🎯 抽象定义

🍔 抽象菜单项类(或接口)
cpp 复制代码
class MenuItem {
public:
    std::string name;
    double price;

    MenuItem(std::string n, double p) : name(n), price(p) {}
    virtual ~MenuItem() = default;
};
🧾 抽象迭代器接口
cpp 复制代码
class Iterator {
public:
    virtual bool hasNext() = 0;
    virtual MenuItem* next() = 0;
    virtual ~Iterator() = default;
};
🧾 抽象菜单接口
cpp 复制代码
class Menu {
public:
    virtual Iterator* createIterator() = 0;
    virtual ~Menu() = default;
};

🍱 示例:不同商家实现

奶茶菜单(用 vector 存)
cpp 复制代码
class MilkTeaMenu : public Menu {
private:
	std::vector<MenuItem> items;
public:
	Iterator* createIterator() override;

	MilkTeaMenu() {
		items.emplace_back("珍珠奶茶", 10);
		items.emplace_back("波霸奶绿", 12);
	}

	void addItem(const MenuItem& item) {
		items.push_back(item);
	}

	const std::vector<MenuItem>& getItems() const {
		return items;
	}

};

class MilkTeaIterator : public Iterator {
private:
	MilkTeaMenu& milkTeaMenu;
	int currentIndex;
public:
	MilkTeaIterator(MilkTeaMenu& coll) : milkTeaMenu(coll), currentIndex(0) {}
	MenuItem getNext() override {
		if (hasMore()) {
			return milkTeaMenu.getItems()[currentIndex++]; 
		}
		return MenuItem("",0);
	}
	bool hasMore() override {
		return currentIndex < milkTeaMenu.getItems().size(); 
	}
};
烧烤菜单(用 list 存)
cpp 复制代码
class BBQMenu : public Menu {
private:
	std::list<MenuItem> items;
public:

	BBQMenu() {
		items.emplace_back("羊肉串", 20);
		items.emplace_back("鸡翅", 40);
	}

	Iterator* createIterator() override;

	void addItem(const MenuItem& item) {
		items.push_back(item);
	}

	const std::list<MenuItem>& getItems() const {
		return items;
	}

};
class BBQIterator : public Iterator {
private:
	BBQMenu& bbqMenu;
	std::list<MenuItem>::const_iterator currentIt;
public:
	BBQIterator(BBQMenu& coll) : bbqMenu(coll) {
		currentIt = bbqMenu.getItems().cbegin();
	}
	MenuItem getNext() override {
		if (hasMore()) {
			// Implementation to get the next element from the collection
			return *currentIt++; // Placeholder
		}
		return MenuItem("", 0);
	}
	bool hasMore() override {

		// Implementation to check if more elements are available
		return currentIt != bbqMenu.getItems().cend(); // Placeholder
	}
};

✅ 客户端统一遍历:

cpp 复制代码
void printMenu(Menu* menu) {
	Iterator* it = menu->createIterator();
	while (it->hasMore()) {
		std::string element = it->getNext().name;
		// Process the element
		std::cout << "element= " << element << std::endl;
	}
	delete it;
}

🧪 使用:

cpp 复制代码
Iterator* MilkTeaMenu::createIterator() {
	return new MilkTeaIterator(*this);
}

Iterator* BBQMenu::createIterator() {
	return new BBQIterator(*this);
}

int main() {
	MilkTeaMenu milkTeaMenu;
	printMenu(&milkTeaMenu);
	BBQMenu bbqMenu;
	printMenu(&bbqMenu);

	return 0;
}

🎯 适用场景总结

适用场景 描述
不同集合类型统一遍历 vector、list、map 等不同结构
隐藏内部结构 客户端不关心菜单内部
支持并发、懒加载遍历 支持自定义迭代顺序和惰性加载等
相关推荐
1000世界小札35 分钟前
《大话数据结构》第9章精读:归并排序与快速排序完整 C++ 实现
数据结构·c++·算法
2601_956121973 小时前
背包基础篇(01、完全、分组、多重、混合)
c++·算法·动态规划
fpcc3 小时前
跟我学C++中级篇——编译期的条件选择
开发语言·c++
ShineWinsu8 小时前
对于C++:C++20中线程、初始化、Lambda与内存视图等特性的解析
c++·c++20
张张的快乐时光呀!9 小时前
记录使用 MFC 打开文件对话框读取一张图片并做简单的灰度转换算法简单学习过程
c++·mfc
东华万里10 小时前
第41篇 C++类与对象核心知识梳理:从底层原理到面试实战
开发语言·c++·大学生专区
qq_5896660511 小时前
C语言、C++与C#的区别详解
c语言·c++·c#
万法若空11 小时前
排列组合恒等式
c++·算法
AI人工智能+电脑小能手12 小时前
大白话说Java设计模式-34-命令模式(业务实战篇)
java·spring·设计模式·命令模式·异步任务·撤销重做·事务封装
老洋葱Mr_Onion12 小时前
【C++】CSP-J初赛模拟卷七错题整理(作者自用)
c++·算法·深度优先