一家早餐店和一家午餐点准备合并在一起,两家的点菜的菜单实现方式如下:
首先,他们的菜单选项都基于同一个类:
package Chapter9_IteratorPattern.Origin;
/**
* @Author 竹心
* @Date 2023/8/17
**/
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 boolean isVegetarian() {
return vegetarian;
}
public double getPrice() {
return price;
}
}
package Chapter9_IteratorPattern.Origin;
import java.util.ArrayList;
import java.util.List;
/**
* @Author 竹心
* @Date 2023/8/17
**/
public class PancakeHouseMenu {
List
package Chapter9_IteratorPattern.Origin;
/**
* @Author 竹心
* @Date 2023/8/17
**/
public class DinerMenu {
static final int MAX_ITEMS = 6;
int numberOfItems = 0;
MenuItem[] menuItems;
public DinerMenu(){
this.menuItems = new MenuItem[MAX_ITEMS];
addItem("aaa","food1",true,2.99);
addItem("bbb","food2",true,2.99);
addItem("ccc","food3",true,3.29);
addItem("ddd","food4",true,3.05);
}
public void addItem(String name,String description,
boolean vegetarian,double price){
MenuItem menuItem = new MenuItem(name,description,vegetarian,price);
if(this.numberOfItems >= MAX_ITEMS){
System.out.println("Sorry! Menu is full!");
}else{
this.menuItems[this.numberOfItems] = menuItem;
this.numberOfItems++;
}
}
public MenuItem[] getMenuItems(){
return this.menuItems;
}
}
可以得知:前者使用List来实现,后者使用数组来实现。
这时候,如果不采取任何方法加以更改,新餐厅的服务员将要这样使用两个菜单:
package Chapter9_IteratorPattern.Origin;
import java.util.List;
/**
* @Author 竹心
* @Date 2023/8/17
**/
public class Waitress {
public void printMenu(){
//遍历菜单
PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();
List breakfastItems = pancakeHouseMenu.getMenuItems();
DinerMenu dinerMenu = new DinerMenu();
MenuItem[] lunchItems = dinerMenu.getMenuItems();
for(int i= 0;i
由此可见:服务员类和两个菜单类直接接触,既违反封装原理,还违背了面向接口编码的原理,同时极其不利于维护。
这时可以采用迭代器模式:在两个菜单和服务员之间加入一个迭代器(iterator),迭代器负责直接处理菜单的遍历等功能,然后服务员通过这个迭代器来使用菜单,成功解耦。
迭代器提供一种方式,可以访问一个聚合对象中的元素而又不暴露其潜在实现。
同时把遍历的任务放到迭代器上而不是聚合上,这就简化了聚合的接口和实现(让聚合只需负责管理对象集合即可),满足单一责任原则。
package Chapter9_IteratorPattern.MyIterator;
/**
* @Author 竹心
* @Date 2023/8/17
**/
public interface Iterator {
//提供一个统一的迭代器接口,在用户和对象集合之间加入迭代器,
//迭代器中含有遍历集合的具体操作,不需要关心如何实现
boolean hasNext();
MenuItem next();
}
package Chapter9_IteratorPattern.MyIterator;
import java.util.List;
/**
* @Author 竹心
* @Date 2023/8/17
**/
public class PancakeHouseIterator implements Iterator{
List items;
int position = 0;
public PancakeHouseIterator(List items){
this.items = items;
}
@Override
public MenuItem next() {
MenuItem menuItem = items.get(position);
position++;
return menuItem;
}
@Override
public boolean hasNext() {
if(position >= items.size() || items.get(position) == null){
return false;
}else{
return true;
}
}
}
加入一个新方法即可:
public Iterator createIterator(){
return new PancakeHouseIterator(menuItems);
}
package Chapter9_IteratorPattern.MyIterator;
/**
* @Author 竹心
* @Date 2023/8/17
**/
public class DinerMenuIterator implements Iterator{
MenuItem[] items;
int position = 0;
public DinerMenuIterator(MenuItem[] items){
this.items = items;
}
@Override
public MenuItem next() {
MenuItem menuItem = items[position];
position++;
return menuItem;
}
@Override
public boolean hasNext() {
if(position >= items.length || items[position] == null){
return false;
}else{
return true;
}
}
}
同理:
public Iterator createIterator(){
//提供一个接口使得迭代器获取到该集合
return new DinerMenuIterator(menuItems);
}
使用自定义迭代器的服务员类:
package Chapter9_IteratorPattern.MyIterator;
/**
* @Author 竹心
* @Date 2023/8/17
**/
public class Waitress {
PancakeHouseMenu pancakeHouseMenu;
DinerMenu dinerMenu;
public Waitress(PancakeHouseMenu pancakeHouseMenu,
DinerMenu dinerMenu){
this.pancakeHouseMenu = pancakeHouseMenu;
this.dinerMenu = dinerMenu;
}
public void printMenu(){
Iterator pancakeMenuIterator = pancakeHouseMenu.createIterator();
Iterator dinerIterator = dinerMenu.createIterator();
System.out.println("MENU\n----\nBREAKFAST");
printMenu(pancakeMenuIterator);
System.out.println("\nLUNCH");
printMenu(dinerIterator);
}
private void printMenu(Iterator iterator){
while(iterator.hasNext()){
MenuItem menuItem = iterator.next();
System.out.println(menuItem.getName()+" ");
System.out.println(menuItem.getPrice()+" ");
System.out.println(menuItem.getDescription()+" ");
}
}
}
package Chapter9_IteratorPattern.MyIterator;
/**
* @Author 竹心
* @Date 2023/8/17
**/
public class MenuTestDrive {
public static void main(String[] args) {
PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();
DinerMenu dinerMenu = new DinerMenu();
Waitress waitress = new Waitress(pancakeHouseMenu,dinerMenu);
waitress.printMenu();
}
}
因为早餐菜单使用了ArrayList,它有iterator()方法返回一个迭代器(所以这里可以删除掉它的自定义迭代器),然而午餐菜单是用数组实现的,没有这个方法,所以午餐类还是需要使用自定义的迭代器(“继承”于java的迭代器)。
添加头文件:
import java.util.Iterator;
然后修改方法:
public Iterator createIterator(){
return menuItems.iterator();
}
package Chapter9_IteratorPattern.JavaIterator;
import java.util.Iterator;
/**
* @Author 竹心
* @Date 2023/8/17
**/
public class DinerMenuIterator implements Iterator{
MenuItem[] items;
int position = 0;
public DinerMenuIterator(MenuItem[] items){
this.items = items;
}
@Override
public MenuItem next() {
MenuItem menuItem = items[position];
position++;
return menuItem;
}
@Override
public boolean hasNext() {
if(position >= items.length || items[position] == null){
return false;
}else{
return true;
}
}
@Override
public void remove() {
//java自带的迭代器是由remove()方法的,所以这里必须要实现
throw new UnsupportedOperationException("you can not remove it!");
}
}
package Chapter9_IteratorPattern.JavaIterator;
import java.util.Iterator;
/**
* @Author 竹心
* @Date 2023/8/18
**/
public interface Menu {
public Iterator> createIterator();
}
记得分别在午餐菜单类和早餐菜单类的类声明那里加上对Menu的实现:
public class DinerMenu implements Menu{...}
public class PancakeHouseMenu implements Menu{...}
package Chapter9_IteratorPattern.JavaIterator;
import java.util.Iterator;
/**
* @Author 竹心
* @Date 2023/8/17
**/
public class Waitress {
Menu pancakeHouseMenu;
Menu dinerMenu;
public Waitress(Menu pancakeHouseMenu,Menu dinerMenu){
this.pancakeHouseMenu = pancakeHouseMenu;
this.dinerMenu = dinerMenu;
}
public void printMenu(){
Iterator> pancakeMenuIterator = pancakeHouseMenu.createIterator();
Iterator> dinerIterator = dinerMenu.createIterator();
System.out.println("MENU\n----\nBREAKFAST");
printMenu(pancakeMenuIterator);
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()+" ");
}
}
}
好了,现在又有一家咖啡店并入餐厅,并在晚上提供服务,这家咖啡店也有它独特的菜单实现方式:使用哈希表!接下来要将它加入迭代器的使用中(这里将其称为晚餐菜单):
package Chapter9_IteratorPattern.AddCafe;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* @Author 竹心
* @Date 2023/8/18
**/
public class CafeMenu implements Menu{
HashMap menuItems = new HashMap();
public CafeMenu() {
addItem("Veggie Burger and Air Fries",
"Veggie burger on a whole wheat bun, lettuce, tomato, and fries",
true, 3.99);
addItem("Soup of the day",
"A cup of the soup of the day, with a side salad",
false, 3.69);
addItem("Burrito",
"A large burrito, with whole pinto beans, salsa, guacamole",
true, 4.29);
}
public void addItem(String name, String description,
boolean vegetarian, double price)
{
MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
menuItems.put(name, menuItem);
}
// public Map getItems() {
// return menuItems;
// }
public Iterator createIterator() {
//获取哈希表中的集合的迭代器
return menuItems.values().iterator();
}
}
package Chapter9_IteratorPattern.AddCafe;
import java.util.Iterator;
/**
* @Author 竹心
* @Date 2023/8/17
**/
public class Waitress {
Menu pancakeHouseMenu;
Menu dinerMenu;
Menu cafeMenu;
public Waitress(Menu pancakeHouseMenu, Menu dinerMenu, Menu cafeMenu){
this.pancakeHouseMenu = pancakeHouseMenu;
this.dinerMenu = dinerMenu;
this.cafeMenu = cafeMenu;
}
public void printMenu(){
Iterator> pancakeMenuIterator = pancakeHouseMenu.createIterator();
Iterator> dinerIterator = dinerMenu.createIterator();
Iterator> cafeIterator = cafeMenu.createIterator();
System.out.println("MENU\n----\nBREAKFAST");
printMenu(pancakeMenuIterator);
System.out.println("\nLUNCH");
printMenu(dinerIterator);
System.out.println("\nDINNER");
printMenu(cafeIterator);
}
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()+" ");
}
}
}
现在,我们发现,如果菜单越来越多,服务员类涉及到的操作也越来越多,所以这里可以对服务员类进行优化:
package headfirst.designpatterns.iterator.transition;
import java.util.*;
/**
* @Author 竹心
* @Date 2023/8/18
**/
public class Waitress {
ArrayList
现在问题来了,如果菜单中存在子菜单,那么又该如何实现呢?
很明显上面的方法已经不适用了,重写菜单代码才行。
这里就引出了组合模式:
《HeadFirst设计模式(第二版)》第九章代码——组合模式_轩下小酌的博客-CSDN博客