👨🎓 模式名称:迭代器模式(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 等不同结构 |
隐藏内部结构 | 客户端不关心菜单内部 |
支持并发、懒加载遍历 | 支持自定义迭代顺序和惰性加载等 |