迭代器模式

【0】README
0.1)本文文字部分描述转自“head first设计模式”,旨在学习 迭代器模式 的基础知识;

【1】迭代器模式
1)定义:迭代器模式提供了一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示;
2)迭代器模式的作用: 迭代器模式让我们能游走于聚合内的每一个元素,而又不暴露其内部的表示;把游走的任务放在迭代器上,而不是聚合上。这样简化了聚合的接口和实现,也让责任各得其所;

【2】迭代器应用场景
2.1)problem:你知道吗? 开封菜要和北京烤鸭合并了(仅仅为了模拟其场景),并组建了新公司,这是个好消息,不过这里有一个问题?——假如我就是新公司的招待员,要求是,能应对顾客的需要打印定制菜单。但是,要知道开封菜的菜单用的是ArrayList存储,而北京烤鸭的菜单用的是数组存储。怎样打印用户的菜单呢?那就是遍历两种不同的菜单项,因为数组列表和数组的遍历方式不一样,所以要采用两次遍历,这似乎很麻烦。

  • step1)MenuItem(菜单项)
  • public class MenuItem {
    	private String name;
    	private String desc;
    	private double price;
    	
    	public MenuItem() {}
    	
    	public MenuItem(String name, String desc, double price) {
    		this.name = name;
    		this.desc = desc;
    		this.price = price;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public String getDesc() {
    		return desc;
    	}
    
    	public double getPrice() {
    		return price;
    	}
    
    	@Override
    	public String toString() {
    		return "name=" + name + ", price=" + price;
    	}
    }
    step2)开封菜的菜单
  • public class KFCMenu {
    	ArrayList<MenuItem> items;
    	
    	public KFCMenu() {
    		items = new ArrayList<>();
    		addItem("hamburger", "hamburger", 2.00);
    		addItem("salad", "salad", 3.00);
    		addItem("french fries", "french fries", 4.00);
    		addItem("chicken", "chicken", 6.00);
    	}
    	
    	public void addItem(String name, String desc , double price) {
    		MenuItem item = new MenuItem(name, desc, price);
    		items.add(item);
    	}
    	
    	public ArrayList getMenuItems() {
    		return items;
    	}
    	
    	//public Iterator<MenuItem> createIterator() {
    	//	return items.iterator();
    	//}
    }
    step3)北京烤鸭的菜单
  • public class BJRoastDuckMenu {
    	private final int MAX_ITEMS = 10;
    	private int capacity = 0;
    	MenuItem[] items;
    	
    	public BJRoastDuckMenu() {
    		items = new MenuItem[MAX_ITEMS];
    		addItem("北京烤鸭", "北京烤鸭", 22.00);
    		addItem("梅花扣肉", "salad", 23.00);
    		addItem("蚂蚁上树", "french fries", 104.00);
    		addItem("东坡肘子", "chicken", 236.00);
    	}
    	
    	public void addItem(String name, String desc , double price) {
    		MenuItem item = new MenuItem(name, desc, price);
    		if(capacity == MAX_ITEMS) {
    			System.out.println("there's no space to store new obj");
    		} else {
    			items[capacity++] = item;
    		}
    	}
    	
    	public MenuItem[] getMenuItems() {
    		return items;
    	}
    	
    	public int getCapacity() {
    		return capacity;
    	}
    	
    	//public Iterator<MenuItem> createIterator() {
    	//	return new BJRoastDuckMenuIterator(items);
    	//}
    }
    step4)测试用例
  • public class OldTraverseTest {
    	public static void main(String[] args) {
    		KFCMenu k_menu = new KFCMenu();
    		BJRoastDuckMenu bj_menu = new BJRoastDuckMenu();
    		
    		ArrayList<MenuItem> list = k_menu.getMenuItems();
    		MenuItem[] items = bj_menu.getMenuItems();
    		
    		System.out.println("=== 北京烤鸭的数组菜单 ===");
    		// 第一次遍历 北京烤鸭的数组菜单
    		for (int i = 0; i < bj_menu.getCapacity(); i++) {
    			System.out.println(items[i]);
    		}
    		
    		System.out.println("=== 开封菜的数组列表菜单 ===");
    		// 第二次遍历 开封菜的数组列表菜单
    		Iterator<MenuItem> iterator = list.iterator();
    		while(iterator.hasNext()) {
    			System.out.println(iterator.next());
    		}			
    	}
    }
    打印结果)
  • === 北京烤鸭的数组菜单 ===
    name=北京烤鸭, price=22.0
    name=梅花扣肉, price=23.0
    name=蚂蚁上树, price=104.0
    name=东坡肘子, price=236.0
    === 开封菜的数组列表菜单 ===
    name=hamburger, price=2.0
    name=salad, price=3.0
    name=french fries, price=4.0
    name=chicken, price=6.0
2.3)solution:交给迭代器模式来处理。迭代器模式需要依赖一个迭代器接口,一旦我们有了这个接口,就可以为各种对象集合实现迭代器:数组,列表,散列表等。
2.4)迭代器模式的遍历方法如下
  • step0)创建 Menu接口,该接口有一个createIterator方法
  • public interface Menu {
    	public Iterator<MenuItem> createIterator();
    }
  • step1)开封菜菜单实现 Menu接口,以添加 createIterator方法
  • public class KFCMenu {
    	ArrayList<MenuItem> items;
    	
    	public KFCMenu() {
    		items = new ArrayList<>();
    		addItem("hamburger", "hamburger", 2.00);
    		addItem("salad", "salad", 3.00);
    		addItem("french fries", "french fries", 4.00);
    		addItem("chicken", "chicken", 6.00);
    	}
    	
    	public void addItem(String name, String desc , double price) {
    		MenuItem item = new MenuItem(name, desc, price);
    		items.add(item);
    	}
    	
    	public ArrayList getMenuItems() {
    		return items;
    	}
    	// 添加的创建迭代器的方法
    	public Iterator<MenuItem> createIterator() {
    		return items.iterator();
    	}
    }
    step2)创建遍历北京烤鸭菜单的迭代器
  • public class BJRoastDuckMenuIterator implements Iterator<MenuItem>{
    	private MenuItem[] items;
    	private int position = 0;
    	
    	public BJRoastDuckMenuIterator(MenuItem[] items) {
    		this.items = items;
    	}
    	
    	@Override
    	public boolean hasNext() {
    		if(position >= items.length || items[position] == null) {
    			return false;
    		} else {
    			return true;
    		}
    	}
    
    	@Override
    	public MenuItem next() {		
    		return items[position++];
    	}
    }
    
    step3)北京烤鸭菜实现Menu接口,以添加 createIterator方法
  • public class BJRoastDuckMenu implements Menu{
    	private final int MAX_ITEMS = 10;
    	private int capacity = 0;
    	MenuItem[] items;
    	
    	public BJRoastDuckMenu() {
    		items = new MenuItem[MAX_ITEMS];
    		addItem("北京烤鸭", "北京烤鸭", 22.00);
    		addItem("梅花扣肉", "salad", 23.00);
    		addItem("蚂蚁上树", "french fries", 104.00);
    		addItem("东坡肘子", "chicken", 236.00);
    	}
    	
    	public void addItem(String name, String desc , double price) {
    		MenuItem item = new MenuItem(name, desc, price);
    		if(capacity == MAX_ITEMS) {
    			System.out.println("there's no space to store new obj");
    		} else {
    			items[capacity++] = item;
    		}
    	}
    	
    	public MenuItem[] getMenuItems() {
    		return items;
    	}
    	
    	public int getCapacity() {
    		return capacity;
    	}
    	// 为北京烤鸭菜单创建迭代器
    	public Iterator<MenuItem> createIterator() {
    		return new BJRoastDuckMenuIterator(items);
    	}
    }
    
    step4)创建服务员,封装遍历菜单的方法
  • public class Waitreee {
    	private KFCMenu k_menu;
    	private BJRoastDuckMenu bj_menu;
    	
    	public Waitreee(KFCMenu k_menu, BJRoastDuckMenu bj_menu) {
    		this.k_menu = k_menu;
    		this.bj_menu = bj_menu;
    	}
    	
    	public void printMenu() {
    		Iterator<MenuItem> k_iterator = k_menu.createIterator();
    		Iterator<MenuItem> bj_iterator = bj_menu.createIterator();
    		
    		System.out.println("====== 开封菜的菜品菜单 ======");
    		printMenu(k_iterator);
    		System.out.println("====== 北京烤鸭的菜品菜单 ======");
    		printMenu(bj_iterator);
    	}
    	
    	private void printMenu(Iterator<MenuItem> iterator) {
    		while(iterator.hasNext()) {
    			System.out.println(iterator.next());
    		}
    	}
    }
    step5)测试用例
  • public class MenuIteratorTest {
    	public static void main(String[] args) {
    		KFCMenu k_menu = new KFCMenu();
    		BJRoastDuckMenu bj_menu = new BJRoastDuckMenu();
    		Waitreee waitreee = new Waitreee(k_menu, bj_menu);
    		
    		waitreee.printMenu();
    	}
    }
    
    打印结果)
  • ====== 开封菜的菜品菜单 ======
    name=hamburger, price=2.0
    name=salad, price=3.0
    name=french fries, price=4.0
    name=chicken, price=6.0
    ====== 北京烤鸭的菜品菜单 ======
    name=北京烤鸭, price=22.0
    name=梅花扣肉, price=23.0
    name=蚂蚁上树, price=104.0
    name=东坡肘子, price=236.0
【3】引入单一责任
3.1)定义:单一责任原则: 表示一个类应该只有一个引起变化的原因;
3.2)类的每个责任都有改变的潜在区域。超过一个责任,意味着找过改变的区域;这个原则告诉我们,尽量让每个类保持单一责任;

【4】对于迭代器模式的扩展
4.1)requirement:现在听说 某品牌咖啡店也要和 开封菜+北京烤鸭合并啦。我们看怎样来遍历它们的菜品
4.2)代码如下(你可以看到,我们只需要添加cafe菜单 和 修改 服务员的代码就可以了)
step1)cafe菜单
public class CafeMenu implements Menu{
	Hashtable<String, MenuItem> items;
	
	public CafeMenu() {
		items = new Hashtable<>();
		addItem("Caramel cafe", "Caramel cafe", 2.00);
		addItem("Mocha", "Mocha", 3.00);
		addItem("black rose", "black rose ", 4.00);
		addItem("irish iced coffee", "irish iced coffee", 6.00);
	}
	
	public void addItem(String name, String desc , double price) {
		MenuItem item = new MenuItem(name, desc, price);
		items.put(item.getName(), item);
	}
	
	@Override
	public Iterator<MenuItem> createIterator() {
		return items.values().iterator();
	}
}
step2)修改女服务员的遍历菜单的代码
public class Waitreee {
	private KFCMenu k_menu;
	private BJRoastDuckMenu bj_menu;
	private CafeMenu cafe_menu;
	
	public Waitreee(KFCMenu k_menu, BJRoastDuckMenu bj_menu, CafeMenu cafe_menu) {
		this.k_menu = k_menu;
		this.bj_menu = bj_menu;
		this.cafe_menu = cafe_menu;
	}
	
	public Waitreee(KFCMenu k_menu, BJRoastDuckMenu bj_menu) {
		this.k_menu = k_menu;
		this.bj_menu = bj_menu;
	}
	
	public void printMenu() {
		Iterator<MenuItem> k_iterator = k_menu.createIterator();
		Iterator<MenuItem> bj_iterator = bj_menu.createIterator();
		Iterator<MenuItem> cafe_iterator = cafe_menu.createIterator();// this line
		
		System.out.println("====== 开封菜的菜品菜单 ======");
		printMenu(k_iterator);
		System.out.println("====== 北京烤鸭的菜品菜单 ======");
		printMenu(bj_iterator);
		System.out.println("====== 咖啡的菜品菜单 ======"); // this line
		printMenu(cafe_iterator);
	}
	
	private void printMenu(Iterator<MenuItem> iterator) {
		while(iterator.hasNext()) {
			System.out.println(iterator.next());
		}
	}
}
step3)client 代码
public class MultipleMenuIteratorTest {
	public static void main(String[] args) {
		KFCMenu k_menu = new KFCMenu();
		BJRoastDuckMenu bj_menu = new BJRoastDuckMenu();
		CafeMenu cafe_menu = new CafeMenu();
		Waitreee waitreee = new Waitreee(k_menu, bj_menu, cafe_menu);
		
		waitreee.printMenu();
	}
}
打印结果)
====== 开封菜的菜品菜单 ======
name=hamburger, price=2.0
name=salad, price=3.0
name=french fries, price=4.0
name=chicken, price=6.0
====== 北京烤鸭的菜品菜单 ======
name=北京烤鸭, price=22.0
name=梅花扣肉, price=23.0
name=蚂蚁上树, price=104.0
name=东坡肘子, price=236.0
====== 咖啡的菜品菜单 ======
name=irish iced coffee, price=6.0
name=Mocha, price=3.0
name=black rose, price=4.0
name=Caramel cafe, price=2.0


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值