迭代器模式提供一种方法顺序访问一个聚合对象中的元素,而又不暴露其内部表示。
假设有餐厅和煎饼屋实体,在系统中他们的数据存储结构不同,现在要同时遍历他们,如何才能做到简单明了。
这是初始代码:
public class MenuItem {
String name;
String description;
boolean vegetarian;
double price;
public MenuItem(String name, String description, boolean vegetarian, double price) {
this.name = name;
this.description = description;
this.vegetarian = vegetarian;
this.price = price;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public double getPrice() {
return price;
}
public boolean isVegetarian() {
return vegetarian;
}
}
public class PancakeHouseMenu {
List<MenuItem> menuItems = new ArrayList<>();
public PancakeHouseMenu() {
menuItems = new ArrayList();
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 gresh blueberries",
true,
3.49);
addItem("Waffles",
"Waffles, with your choice of blueberries or strawberries",
true,
3.59);
}
public void addItem(String name,
String description,
boolean vegetarian,
double price) {
MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
menuItems.add(menuItem);
}
public List<MenuItem> getMenuItems() {
return menuItems;
}
}
public class DinerMenu {
static final int MAX_ITEMS = 6;
int numberOfItems = 0;
MenuItem[] menuItems;
public DinerMenu() {
menuItems = new MenuItem[MAX_ITEMS];
addItem("Vegetarian BLT",
"(Faking') Bacon with lettuce & tomato on whole wheat",
true,
2.99);
addItem("BLT",
"Bacon with lettuce & tomato on whole wheat",
false,
3.29);
addItem("Hot dog",
"A hot dog, with sauerkraut, relish, onions, topped with cheese",
false,
3.05);
}
public void addItem(String name,
String description,
boolean vegetarian,
double price) {
MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
if (numberOfItems >= MAX_ITEMS) {
System.err.println("Sorry, menu is full! Can‘t add item to menu");
} else {
menuItems[numberOfItems] = menuItem;
numberOfItems = numberOfItems + 1;
}
}
public MenuItem[] getMenuItems() {
return menuItems;
}
}
这样在遍历的时候就需要同时考虑餐厅和煎饼屋的两种遍历方式,一个是列表遍历一个数组遍历,所以为了将遍历的过程从各种集合或数组结构中解耦出来,采用迭代器模式做如下改进:
public interface Iterator {
boolean hasNext();
Object next();
}
public class MenuItem {
String name;
String description;
boolean vegetarian;
double price;
public MenuItem(String name, String description, boolean vegetarian, double price) {
this.name = name;
this.description = description;
this.vegetarian = vegetarian;
this.price = price;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public double getPrice() {
return price;
}
public boolean isVegetarian() {
return vegetarian;
}
}
public class DinerMenu {
static final int MAX_ITEMS = 6;
int numberOfItems = 0;
MenuItem[] menuItems;
public DinerMenu() {
menuItems = new MenuItem[MAX_ITEMS];
addItem("Vegetarian BLT",
"(Faking') Bacon with lettuce & tomato on whole wheat",
true,
2.99);
addItem("BLT",
"Bacon with lettuce & tomato on whole wheat",
false,
3.29);
addItem("Hot dog",
"A hot dog, with sauerkraut, relish, onions, topped with cheese",
false,
3.05);
}
public void addItem(String name,
String description,
boolean vegetarian,
double price) {
MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
if (numberOfItems >= MAX_ITEMS) {
System.err.println("Sorry, menu is full! Can‘t add item to menu");
} else {
menuItems[numberOfItems] = menuItem;
numberOfItems = numberOfItems + 1;
}
}
public Iterator createIterator() {
return new DinerMenuIterator(menuItems);
}
}
public class DinerMenuIterator implements Iterator {
MenuItem[] items;
int position = 0;
public DinerMenuIterator(MenuItem[] items) {
this.items = items;
}
@Override
public boolean hasNext() {
if (position >= items.length || items[position] == null) {
return false;
} else {
return true;
}
}
@Override
public Object next() {
MenuItem menuItem = items[position];
position = position + 1;
return menuItem;
}
}
public class PancakeHouseMenu {
List<MenuItem> menuItems = new ArrayList<>();
public PancakeHouseMenu() {
menuItems = new ArrayList<>();
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 gresh blueberries",
true,
3.49);
addItem("Waffles",
"Waffles, with your choice of blueberries or strawberries",
true,
3.59);
}
public void addItem(String name,
String description,
boolean vegetarian,
double price) {
MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
menuItems.add(menuItem);
}
public Iterator createIterator() {
return new PancakeHouseMenuIterator(menuItems);
}
}
public class PancakeHouseMenuIterator implements Iterator {
List<MenuItem> items;
int index = 0;
public PancakeHouseMenuIterator(List<MenuItem> items) {
this.items = items;
}
@Override
public boolean hasNext() {
return index < items.size();
}
@Override
public Object next() {
return items.get(index++);
}
}
public class Waitress {
PancakeHouseMenu pancakeHouseMenu;
DinerMenu dinerMenu;
public Waitress(PancakeHouseMenu pancakeHouseMenu, DinerMenu dinerMenu) {
this.pancakeHouseMenu = pancakeHouseMenu;
this.dinerMenu = dinerMenu;
}
public void printMenu() {
Iterator pancakeIterator = pancakeHouseMenu.createIterator();
Iterator dinerIterator = dinerMenu.createIterator();
System.out.println("MENU\n----\nBREAKFAST");
printMenu(pancakeIterator);
System.out.println("\nLUNCH");
printMenu(dinerIterator);
}
private void printMenu(Iterator iterator) {
while (iterator.hasNext()) {
MenuItem menuItem = (MenuItem) iterator.next();
System.out.println(menuItem.getName() + ", ");
System.out.println(menuItem.getPrice() + " -- ");
System.out.println(menuItem.getDescription());
}
}
}
代码改进后,服务员实体能用通用的迭代器模式遍历各种菜单,但是服务员初始化代码貌似与各类菜单类耦合了,这并不是我们想要的,所以进一步优化代码:
现在抽象出菜单接口,并在服务原实体中对具体菜单进行解耦:
public interface Menu {
public Iterator createIterator();
}
public class Waitress {
Menu pancakeHouseMenu;
Menu dinerMenu;
public Waitress(Menu pancakeHouseMenu, Menu dinerMenu) {
this.pancakeHouseMenu = pancakeHouseMenu;
this.dinerMenu = dinerMenu;
}
public void printMenu() {
Iterator pancakeIterator = pancakeHouseMenu.createIterator();
Iterator dinerIterator = dinerMenu.createIterator();
System.out.println("MENU\n----\nBREAKFAST");
printMenu(pancakeIterator);
System.out.println("\nLUNCH");
printMenu(dinerIterator);
}
private void printMenu(Iterator iterator) {
while (iterator.hasNext()) {
MenuItem menuItem = (MenuItem) iterator.next();
System.out.println(menuItem.getName() + ", ");
System.out.println(menuItem.getPrice() + " -- ");
System.out.println(menuItem.getDescription());
}
}
}
修改代码之后,貌似和具体菜单类进行了解耦,但是每次加入新菜单时,依然要修改服务员实体类,在构造函数中再增加一个参数,这并不遵循对修改关闭原则,所以我们需要优化菜单遍历过程,使其不会因为增加新的菜单项而修改原有的服务员代码。并且我们在这引入单一责任设计原则:一个类应该只有一个引起变化的原因。服务员类主要职责是管理菜单项。所以我们需要实现:
- 菜单遍历
- 遵循单一设计原则
这就需要组合模式来实现了
发表回复