之前的总结:

https://blog.csdn.net/u011109881/article/details/59677544

个人觉得本章节,HeadFirst讲的没有之前看到的网站讲的清晰,至少在迭代器这部分是的;不过,head first书中讲的更详细些。本节还是采用Head First中的例子来描述迭代器模式。

情景再现

现有两家店的实现方式不同,一个采用ArrayList,一个采用数组;现需要对所有菜单遍历,那么做法一般会是如下形式:
首先菜单的model类:

public class MenuItem {String name;String description;boolean vegetarian;double price;public MenuItem(String name, String description, boolean vegetarian,double price) {super();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;}@Overridepublic String toString() {return "name =" + name + " description " + description+ " isVegetarian " + vegetarian + " price= " + price;}
}

两家店菜单的实现:

public class DinerMenu {static final int MAX_ITEMS = 6;public int numberOfItems = 0;MenuItem[] menuItems;public DinerMenu() {menuItems = new MenuItem[MAX_ITEMS];addMenuItem("Diner Menu1", "xxxxx", true, 3.99);addMenuItem("Diner with meat", "xxxxx", false, 4.99);addMenuItem("Diner Menu2", "xxxxx", true, 4.49);addMenuItem("Diner with pork", "xxxx", false, 5.99);}public MenuItem[] getMenuItems() {return menuItems;}public void addMenuItem(String name, String description,boolean vegetarian, double price) {MenuItem item = new MenuItem(name, description, vegetarian, price);if (numberOfItems >= MAX_ITEMS) {System.out.println("menu is full! Can't add item to menu any more");} else {menuItems[numberOfItems] = item;numberOfItems++;}}
}
public class PancakeHouseMenu {ArrayList<MenuItem> menuItems;public PancakeHouseMenu() {menuItems = new ArrayList<MenuItem>();addMenuItem("Pancake Breakfast1", "xxxxx", true, 2.99);addMenuItem("Pancake Breakfast with meat", "xxxxx", false, 3.99);addMenuItem("Pancake Breakfast", "xxxxx", true, 3.49);addMenuItem("Pancake Breakfast with pork", "xxxx", false, 4.99);}public ArrayList<MenuItem> getMenuItems() {return menuItems;}public void addMenuItem(String name,String description,boolean vegetarian,double price) {MenuItem item = new MenuItem(name, description, vegetarian, price);menuItems.add(item);}}

输出类的普通实现:

public class Printer1 {public static void main(String[] args) {PancakeHouseMenu breakfastMenu = new PancakeHouseMenu();ArrayList<MenuItem> breakfastList = breakfastMenu.getMenuItems();for (MenuItem item : breakfastList) {System.out.println(item.toString());}DinerMenu dinerMenu = new DinerMenu();MenuItem[] dinerList = dinerMenu.getMenuItems();for (int i = 0; i < dinerMenu.numberOfItems; i++) {System.out.println(dinerList[i].toString());}}}

这里可以看到,当实现种类有多少种,则循环需要执行多少次,也就意味着代码会根据实际情况变得复杂;要避免这种情况,就要用到本章的设计模式迭代器了。

添加迭代器

对于数组,没有现成的迭代器,需要自定义迭代器:(当然也可以继承util包里的Iterator)

package iterator;public interface Iterator {boolean hasNext();Object next();
}
package iterator;import bean.MenuItem;public class DinerMenuIterator implements Iterator {MenuItem[] items;int pos = 0;public DinerMenuIterator(MenuItem[] items) {this.items = items;}public boolean hasNext() {if (pos >= items.length || items[pos] == null) {return false;} else {return true;}}public Object next() {MenuItem item = items[pos];pos++;return item;}}

对DinerMenu稍作修改,去掉getItems方法,添加获取Iterator方法

package bean;import iterator.DinerMenuIterator;public class DinerMenu {static final int MAX_ITEMS = 6;public int numberOfItems = 0;MenuItem[] menuItems;DinerMenuIterator iterator;//变动public DinerMenu() {menuItems = new MenuItem[MAX_ITEMS];addMenuItem("Diner Menu1", "xxxxx", true, 3.99);addMenuItem("Diner with meat", "xxxxx", false, 4.99);addMenuItem("Diner Menu2", "xxxxx", true, 4.49);addMenuItem("Diner with pork", "xxxx", false, 5.99);iterator = new DinerMenuIterator(menuItems);//变动}//// public MenuItem[] getMenuItems() {// return menuItems;// }//public void addMenuItem(String name, String description,boolean vegetarian, double price) {MenuItem item = new MenuItem(name, description, vegetarian, price);if (numberOfItems >= MAX_ITEMS) {System.out.println("menu is full! Can't add item to menu any more");} else {menuItems[numberOfItems] = item;numberOfItems++;}}//新增方法public DinerMenuIterator getIterator() {return this.iterator;}
}

而对于breakfastMenu则简单的多,因为breakfastMenu实现是ArrayList,可以直接返回ArrayList的itorator。注意,此处代码和书中不同,此处的Iterator和上面自定义的Iterator并不是同一个Iterator

public class PancakeHouseMenu {ArrayList<MenuItem> menuItems;public PancakeHouseMenu() {menuItems = new ArrayList<MenuItem>();addMenuItem("Pancake Breakfast1", "xxxxx", true, 2.99);addMenuItem("Pancake Breakfast with meat", "xxxxx", false, 3.99);addMenuItem("Pancake Breakfast", "xxxxx", true, 3.49);addMenuItem("Pancake Breakfast with pork", "xxxx", false, 4.99);}//  public ArrayList<MenuItem> getMenuItems() {//      return menuItems;
//  }public void addMenuItem(String name,String description,boolean vegetarian,double price) {MenuItem item = new MenuItem(name, description, vegetarian, price);menuItems.add(item);}public Iterator<MenuItem> getIterator(){return menuItems.iterator();}}

测试方法略作修改:

public class Printer2 {public static void main(String[] args) {PancakeHouseMenu breakfastMenu = new PancakeHouseMenu();Iterator<MenuItem> iterator1 = breakfastMenu.getIterator();while (iterator1.hasNext()) {System.out.println(iterator1.next());}DinerMenu dinerMenu = new DinerMenu();iterator.Iterator iterator2 = dinerMenu.getIterator();while (iterator2.hasNext()) {System.out.println(iterator2.next());}}}

看上去形式统一了呢。
此时的类结构:

再改进:全部使用util的Iterator

Java util包中的Iterator和我们自定义的Iterator其实是类似的,之所以先用自定义的Iterator,是因为这样做可以更了解Java的Iterator的实现原理
Java自带的Itorator:

package java.util;import java.util.function.Consumer;/*** An iterator over a collection.  {@code Iterator} takes the place of* {@link Enumeration} in the Java Collections Framework.  Iterators* differ from enumerations in two ways:** <ul>*      <li> Iterators allow the caller to remove elements from the*           underlying collection during the iteration with well-defined*           semantics.*      <li> Method names have been improved.* </ul>** <p>This interface is a member of the* <a href="{@docRoot}/../technotes/guides/collections/index.html">* Java Collections Framework</a>.** @param <E> the type of elements returned by this iterator** @author  Josh Bloch* @see Collection* @see ListIterator* @see Iterable* @since 1.2*/
public interface Iterator<E> {/*** Returns {@code true} if the iteration has more elements.* (In other words, returns {@code true} if {@link #next} would* return an element rather than throwing an exception.)** @return {@code true} if the iteration has more elements*/boolean hasNext();/*** Returns the next element in the iteration.** @return the next element in the iteration* @throws NoSuchElementException if the iteration has no more elements*/E next();/*** Removes from the underlying collection the last element returned* by this iterator (optional operation).  This method can be called* only once per call to {@link #next}.  The behavior of an iterator* is unspecified if the underlying collection is modified while the* iteration is in progress in any way other than by calling this* method.** @implSpec* The default implementation throws an instance of* {@link UnsupportedOperationException} and performs no other action.** @throws UnsupportedOperationException if the {@code remove}*         operation is not supported by this iterator** @throws IllegalStateException if the {@code next} method has not*         yet been called, or the {@code remove} method has already*         been called after the last call to the {@code next}*         method*/default void remove() {throw new UnsupportedOperationException("remove");}/*** Performs the given action for each remaining element until all elements* have been processed or the action throws an exception.  Actions are* performed in the order of iteration, if that order is specified.* Exceptions thrown by the action are relayed to the caller.** @implSpec* <p>The default implementation behaves as if:* <pre>{@code*     while (hasNext())*         action.accept(next());* }</pre>** @param action The action to be performed for each element* @throws NullPointerException if the specified action is null* @since 1.8*/default void forEachRemaining(Consumer<? super E> action) {Objects.requireNonNull(action);while (hasNext())action.accept(next());}
}

可以看到,主体和自定义的Iterator还是类似的。
对于PancakeHouseMenu基本没有变动

public class PancakeHouseMenu {ArrayList<MenuItem> menuItems;public PancakeHouseMenu() {menuItems = new ArrayList<MenuItem>();addMenuItem("Pancake Breakfast1", "xxxxx", true, 2.99);addMenuItem("Pancake Breakfast with meat", "xxxxx", false, 3.99);addMenuItem("Pancake Breakfast", "xxxxx", true, 3.49);addMenuItem("Pancake Breakfast with pork", "xxxx", false, 4.99);}public void addMenuItem(String name,String description,boolean vegetarian,double price) {MenuItem item = new MenuItem(name, description, vegetarian, price);menuItems.add(item);}public Iterator<MenuItem> createIterator(){return menuItems.iterator();}}

DinerMenuIterator的基本实现不需要变动,就换个导包即可

public class DinerMenuIterator implements Iterator<MenuItem> {MenuItem[] items;int pos = 0;public DinerMenuIterator(MenuItem[] items) {this.items = items;}public boolean hasNext() {if (pos >= items.length || items[pos] == null) {return false;} else {return true;}}public MenuItem next() {MenuItem item = items[pos];pos++;return item;}
}

dinerMenu则也需要重新导入Iterator的包

public class DinerMenu {static final int MAX_ITEMS = 6;public int numberOfItems = 0;MenuItem[] menuItems;Iterator<MenuItem> iterator;public DinerMenu() {menuItems = new MenuItem[MAX_ITEMS];addMenuItem("Diner Menu1", "xxxxx", true, 3.99);addMenuItem("Diner with meat", "xxxxx", false, 4.99);addMenuItem("Diner Menu2", "xxxxx", true, 4.49);addMenuItem("Diner with pork", "xxxx", false, 5.99);iterator = new DinerMenuIterator(menuItems);}public void addMenuItem(String name, String description,boolean vegetarian, double price) {MenuItem item = new MenuItem(name, description, vegetarian, price);if (numberOfItems >= MAX_ITEMS) {System.out.println("menu is full! Can't add item to menu any more");} else {menuItems[numberOfItems] = item;numberOfItems++;}}public Iterator<MenuItem> createIterator() {return this.iterator;}
}

测试类稍作整修

    public static void main(String[] args) {PancakeHouseMenu breakfastMenu = new PancakeHouseMenu();Iterator<MenuItem> iterator1 = breakfastMenu.createIterator();while (iterator1.hasNext()) {System.out.println(iterator1.next());}DinerMenu dinerMenu = new DinerMenu();Iterator<MenuItem> iterator2 = dinerMenu.createIterator();while (iterator2.hasNext()) {System.out.println(iterator2.next());}}

输出结果仍然不变:

name =Pancake Breakfast1 description xxxxx isVegetarian true price= 2.99
name =Pancake Breakfast with meat description xxxxx isVegetarian false price= 3.99
name =Pancake Breakfast description xxxxx isVegetarian true price= 3.49
name =Pancake Breakfast with pork description xxxx isVegetarian false price= 4.99
name =Diner Menu1 description xxxxx isVegetarian true price= 3.99
name =Diner with meat description xxxxx isVegetarian false price= 4.99
name =Diner Menu2 description xxxxx isVegetarian true price= 4.49
name =Diner with pork description xxxx isVegetarian false price= 5.99

但是类的结构图却已经变化:

注意,此处类图与书中不同(主要是没有实现Menu接口以及女招待对象),属个人理解。如有错误,请指出

迭代器模式的作用

  1. 迭代器的出现,让我们无需关心相关model的实现结构
  2. 将数据的遍历抽离出来,使得单一职责原则能够很好的实现。

迭代器的替换

事实上,JDK 1.5新增了增强的for循环,让我们对于Collections的集合类,遍历更加方便,对于任意Collections,我们都可以这样遍历:

        for(Object m :items){System.out.println("xxxx");}

这样即使不使用Iterator,我们仍然可以遍历元素

迭代器的多次使用

之前,我的实现与书中不同,以为实现Menu接口并无甚用,后面才发现,是为了遍历Menu而做的铺垫。书中最后的迭代器实例,先对存放Menu集合的list进行遍历,之后,对每个menu内的Item项进行遍历。因此,有两次Iterator的使用。现实现如下:(需对上述代码略作修改)
增加Menu接口

public interface Menu {public Iterator<MenuItem> createIterator();
}

让DinerMenu PancakeHouseMenu都实现Menu接口;因为之前是直接写了createIterator方法,因此这次只需在后面加上 implements Menu即可

添加Waitress类的实现

public class Waitress {ArrayList<Menu> menus;public Waitress(Menu dinerMenu,Menu pancakeHouseMenu) {menus = new ArrayList<Menu>();menus.add(dinerMenu);menus.add(pancakeHouseMenu);}public void printMenu(){Iterator<Menu> menusIterator = menus.iterator();while(menusIterator.hasNext()){printMenu(menusIterator.next().createIterator());}//      for(Menu menu : menus){//          printMenu(menu.createIterator());
//      }}private void printMenu(Iterator<MenuItem> iterator) {while (iterator.hasNext()) {System.out.println(iterator.next());}}
}

修改测试类

public class Printer2 {public static void main(String[] args) {PancakeHouseMenu breakfastMenu = new PancakeHouseMenu();DinerMenu dinerMenu = new DinerMenu();Waitress w = new Waitress(dinerMenu, breakfastMenu);w.printMenu();}}

输出不变

name =Diner Menu1 description xxxxx isVegetarian true price= 3.99
name =Diner with meat description xxxxx isVegetarian false price= 4.99
name =Diner Menu2 description xxxxx isVegetarian true price= 4.49
name =Diner with pork description xxxx isVegetarian false price= 5.99
name =Pancake Breakfast1 description xxxxx isVegetarian true price= 2.99
name =Pancake Breakfast with meat description xxxxx isVegetarian false price= 3.99
name =Pancake Breakfast description xxxxx isVegetarian true price= 3.49
name =Pancake Breakfast with pork description xxxx isVegetarian false price= 4.99

Head First设计模式读书笔记八 第九章上 迭代器模式相关推荐

  1. Head First设计模式读书笔记八 第九章下 组合模式

    之前的总结链接: https://blog.csdn.net/u011109881/article/details/58710579 对比headFirst书中的例子,我觉得书中的组合模式的例子比上面 ...

  2. Think in Java第四版 读书笔记4第九章第十章

    第九章 抽象类与接口 9.1抽象类和抽象接口 抽象类可以有具体实现的方法(并不是所有方法都是abstract的)(比如这样 abstract void test3();) 子类继承抽象类要么要实现(覆 ...

  3. JS高级程序设计读书笔记 (第九章 客户端检测)

    第九章 客户端检测 能力检测 最常用也最为人们广泛接受的客户端检测形式是能力检测(又称特性检测).能力检测的目标不是识别特定的浏览器,而是识别浏览器的能力.采用这种方式不必顾及特定的浏览器如何如何,只 ...

  4. 《HeadFirst设计模式》读书笔记-第9章v2-组合模式

    定义 组合模式(composite pattern)允许你将对象组合成树形结构来表现"整体/部分"层次结构.组合能让客户以一致的方式处理个别对象以及对象组合. 代码实现 本章使用组 ...

  5. 《Head First设计模式》读书笔记 -- (第一章)策略模式

    本文属贫僧不吃肉原创,欢迎转载,转载请注明来自 http://never-say-never.iteye.com/blog/851923 在开始之前,先熟悉一下OO设计的一些原则. OO设计原则之一: ...

  6. 《大话设计模式》读书笔记-第8章 工厂方法模式

    1.工厂方法(Factory Method),定义一个用于创建对象的接口,让子类决定实例化哪一个类.工厂方法是一个类的实例化延迟到其子类. 2.工厂方法(Factory Method)结构图 3.工厂 ...

  7. java2第九章的总结_java并发的艺术-读书笔记-第九章线程池

    使用线程池的好处: 1.降低资源消耗:减少了线程创建和销毁的资源消耗 2.提高响应速度,当任务到达时,线程可以不尽兴创建直接处理 3.提高线程的可管理性.使用线程池可以对线程进行统一的管理,监控,使用 ...

  8. 《期权、期货及其他衍生产品》读书笔记(第九章:价值调节量)

    前言 信用价值调节量(Credit Valuation Adjustment, CVA) 债务价值调节量(Debit Valuation Adjustment, DVA) 融资价值调节量(Fundin ...

  9. JavaScript模式读书笔记 第5章 对象创建模式

    1,命名空间模式  namespace   <script> var myApp = {};//通过全局变量来实现命名空间 maApp.Parent = function (){   }; ...

最新文章

  1. HDU1899 Sum the K-th's(树状数组)
  2. 碰到IBM笔记本电脑无线网络故障确认与排除方法
  3. 实验研究信标无线电能输出功率的因素
  4. EPSON机器人SPLE+语言_简单实例
  5. Springboot2.1.3 + redis 实现 cache序列化乱码问题
  6. CORS with Spring MVC--转
  7. python函数式编程、高阶函数
  8. Python的GUI的最终选择Tkinter的初体验
  9. java jvm对象_【Java】JVM
  10. 独家对话谢宝友:做一款类似于 Linux 的国产操作系统 | 人物志
  11. Python 为什么没有 main 函数?为什么我不推荐写 main 函数?
  12. 无法解析的外部符号+_mysql_fetch_row_vs连接mysql出现以下错误,求解答,谢谢,不胜感激...
  13. 36 如何营造一种活跃的科研气氛/如何培养表达交流能力
  14. CodeForces - 801C Voltage Keepsake 二分
  15. Android:复杂listview条目
  16. HCIE-Security Day39:理论学习:隐私保护
  17. RecyclerView混合布局
  18. 高级shell编程讲解
  19. 安装已经下载好的whl文件
  20. 牛顿迭代法求解开根号、泰勒展开式求解arctan及cordic的原理

热门文章

  1. Ubuntu 出现 Invalid operation update 或 Invalid operation upgrade的解决办法
  2. 2977,3110 二叉堆练习1,3——codevs
  3. Maven配置SpringMVC4+Spring4+Mybatis3环境
  4. 第二百六十四节,Tornado框架-基于正则的动态路由映射分页数据获取计算
  5. 管理nuget程序包中搜索不到任何程序包
  6. RecyclerView 小记
  7. RTT的IPC机制篇——消息队列
  8. 计算机各种硬盘的规格,硬盘规格参数表大全
  9. C语言课后习题(64)
  10. flyway版本号_Spring Boot 集成 Flyway 实现数据库版本控制