组合模式 + 迭代器模式
组合模式和迭代器模式经常组合使用,主要用于处理树形结构的数据并对其进行遍历操作。组合模式负责构建层次化的对象结构,而迭代器模式则提供了统一的方式来遍历这些对象结构。
1. 使用场景
组合模式和迭代器模式的组合非常适合以下场景:
- 文件系统: 文件夹和文件的组合,迭代器可以用于遍历整个文件系统。
- 菜单系统: 多级菜单的管理,迭代器可以用于逐项遍历菜单项。
- 组织架构: 部门和子部门的层次结构,迭代器用于遍历所有部门和员工。
2. 实现示例:菜单系统
我们来实现一个餐厅的菜单系统,其中菜单项(叶子节点)和菜单(组合节点)构成树形结构。组合模式用于管理菜单和菜单项的层次关系,迭代器模式用于遍历所有的菜单项。
(1) 定义组件接口
MenuComponent作为统一接口,定义了菜单项和菜单的公共操作。
// 组件接口
public abstract class MenuComponent {
public void add(MenuComponent menuComponent) {
throw new UnsupportedOperationException();
}
public void remove(MenuComponent menuComponent) {
throw new UnsupportedOperationException();
}
public MenuComponent getChild(int i) {
throw new UnsupportedOperationException();
}
public String getName() {
throw new UnsupportedOperationException();
}
public String getDescription() {
throw new UnsupportedOperationException();
}
public boolean isVegetarian() {
throw new UnsupportedOperationException();
}
public double getPrice() {
throw new UnsupportedOperationException();
}
public void print() {
throw new UnsupportedOperationException();
}
public Iterator<MenuComponent> createIterator() {
throw new UnsupportedOperationException();
}
}
(2) 定义叶子节点
MenuItem类是叶子节点,表示菜单中的单个项。
// 菜单项(叶子节点)
public class MenuItem extends MenuComponent {
private String name;
private String description;
private boolean vegetarian;
private double price;
public MenuItem(String name, String description, boolean vegetarian, double price) {
this.name = name;
this.description = description;
this.vegetarian = vegetarian;
this.price = price;
}
@Override
public String getName() {
return name;
}
@Override
public String getDescription() {
return description;
}
@Override
public boolean isVegetarian() {
return vegetarian;
}
@Override
public double getPrice() {
return price;
}
@Override
public void print() {
System.out.print(" " + getName());
if (isVegetarian()) {
System.out.print("(v)");
}
System.out.println(", " + getPrice());
System.out.println(" -- " + getDescription());
}
}
(3) 定义组合节点
Menu类是组合节点,表示菜单,可以包含子菜单或菜单项。
// 菜单(组合节点)
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Menu extends MenuComponent {
private List<MenuComponent> menuComponents = new ArrayList<>();
private String name;
private String description;
public Menu(String name, String description) {
this.name = name;
this.description = description;
}
@Override
public void add(MenuComponent menuComponent) {
menuComponents.add(menuComponent);
}
@Override
public void remove(MenuComponent menuComponent) {
menuComponents.remove(menuComponent);
}
@Override
public MenuComponent getChild(int i) {
return menuComponents.get(i);
}
@Override
public String getName() {
return name;
}
@Override
public String getDescription() {
return description;
}
@Override
public void print() {
System.out.println("\n" + getName());
System.out.println(", " + getDescription());
System.out.println("---------------------");
Iterator<MenuComponent> iterator = menuComponents.iterator();
while (iterator.hasNext()) {
MenuComponent menuComponent = iterator.next();
menuComponent.print();
}
}
@Override
public Iterator<MenuComponent> createIterator() {
return menuComponents.iterator();
}
}
(4) 客户端代码
客户端代码创建了一个包含多个菜单和菜单项的层次结构,并使用组合模式和迭代器模式进行遍历和打印。
public class Client {
public static void main(String[] args) {
// 创建菜单项
MenuComponent pancakeHouseMenu = new Menu("PANCAKE HOUSE MENU", "Breakfast");
MenuComponent dinerMenu = new Menu("DINER MENU", "Lunch");
MenuComponent cafeMenu = new Menu("CAFE MENU", "Dinner");
MenuComponent allMenus = new Menu("ALL MENUS", "All menus combined");
// 将子菜单加入到顶级菜单中
allMenus.add(pancakeHouseMenu);
allMenus.add(dinerMenu);
allMenus.add(cafeMenu);
// 添加菜单项到子菜单
pancakeHouseMenu.add(new MenuItem("K&B's Pancake Breakfast", "Pancakes with scrambled eggs, and toast", true, 2.99));
pancakeHouseMenu.add(new MenuItem("Regular Pancake Breakfast", "Pancakes with fried eggs, sausage", false, 2.99));
dinerMenu.add(new MenuItem("Vegetarian BLT", "(Fakin’) Bacon with lettuce & tomato on whole wheat", true, 2.99));
dinerMenu.add(new MenuItem("BLT", "Bacon with lettuce & tomato on whole wheat", false, 2.99));
cafeMenu.add(new MenuItem("Veggie Burger and Air Fries", "Veggie burger on a whole wheat bun, lettuce, tomato, and fries", true, 3.99));
cafeMenu.add(new MenuItem("Soup of the day", "A cup of the soup of the day, with a side salad", false, 3.69));
// 打印整个菜单结构
allMenus.print();
}
}
运行结果:
ALL MENUS
, All menus combined
---------------------
PANCAKE HOUSE MENU
, Breakfast
---------------------
K&B's Pancake Breakfast(v), 2.99
-- Pancakes with scrambled eggs, and toast
Regular Pancake Breakfast, 2.99
-- Pancakes with fried eggs, sausage
DINER MENU
, Lunch
---------------------
Vegetarian BLT(v), 2.99
-- (Fakin’) Bacon with lettuce & tomato on whole wheat
BLT, 2.99
-- Bacon with lettuce & tomato on whole wheat
CAFE MENU
, Dinner
---------------------
Veggie Burger and Air Fries(v), 3.99
-- Veggie burger on a whole wheat bun, lettuce, tomato, and fries
Soup of the day, 3.69
-- A cup of the soup of the day, with a side salad
3. 优点
- 组合模式的层次管理: 菜单和菜单项可以组合成树形结构,方便管理和维护。
- 迭代器模式的统一遍历: 使用迭代器模式可以对组合节点和叶子节点进行统一遍历,无需关心具体类型。
- 灵活性高: 组合模式使得菜单结构可以自由扩展,迭代器模式简化了遍历逻辑。
4. 总结
组合模式适合处理树形结构中的“部分-整体”关系,而迭代器模式为复杂的树形结构提供了统一的遍历方式。两者的组合是许多应用场景(如文件系统、菜单系统、组织架构)中的经典设计模式,有助于构建灵活、可扩展的系统。

被折叠的 条评论
为什么被折叠?



