正文

一、定义

迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。

要点:

  • 迭代器模式把在元素之间游走的责任交给迭代器,而不是聚合对象。这样简化了聚合的接口和实现,也让责任各得其所。

二、实现步骤

1、创建迭代器接口

/**
* 迭代器接口
*/
public interface Iterator { /**
* 是否有下一个元素
*/
public boolean hasNext(); /**
* 获取下一个元素
*/
public Object next();
}

2、创建具体迭代器,并实现迭代器接口

具体迭代器负责遍历元素,以及管理目前遍历的位置。

/**
* 具体迭代器
*/
public class ConcreteIterator implements Iterator { /**
* 要遍历的集合(数组)
*/
public String[] items;
/**
* 当前遍历位置
*/
int position = 0; public ConcreteIterator(String[] items) {
this.items = items;
} @Override
public boolean hasNext() {
if (position < items.length) {
return true;
}
return false;
} @Override
public Object next() {
if (!this.hasNext()) {
return null;
}
String item = items[position];
position = position + 1;
return item;
}
}

3、创建聚合接口,并定义返回迭代器的方法

/**
* 聚合接口
*/
public interface Aggregate { /**
* 创建迭代器
*/
public Iterator createIterator();
}

4、创建具体聚合,并实现返回迭代器的方法

具体聚合里面持有集合。这里的集合指的是一群对象,其存储方式可以是列表、数组、散列表等。

/**
* 具体聚合
*/
public class ConcreteAggregate implements Aggregate { /**
* 持有集合(比如列表、数组、散列表等)
*/
public String[] items = new String[] {"item1", "item2", "item3"}; @Override
public Iterator createIterator() {
return new ConcreteIterator(items);
}
}

5、使用迭代器进行遍历

public class Test {

    public static void main(String[] args) {
// 聚合对象
Aggregate aggregate = new ConcreteAggregate();
// 迭代器
Iterator iterator = aggregate.createIterator();
// 遍历
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}

三、举个栗子

1、背景

对象村餐厅和对象村煎饼屋合并了,现在我们可以在同一个地方,享用煎饼屋美味的煎饼早餐和好吃的餐厅午餐了。

假设你被他们合组的新公司雇佣,打算创建一个 Java 版本的女招待。这个 Java 版本的女招待规格是:能应对顾客的需要打印定制的菜单,而无需询问厨师。

现在,有一点小麻烦:煎饼屋菜单使用 ArrayList 记录菜单项,而餐厅则是使用数组记录菜单项。两者都不愿意改变他们的实现,毕竟有太多代码依赖于它们了。

好消息是,煎饼屋和餐厅都同意实现一个统一的菜单项 MenuItem。

2、实现

将集合的遍历交给迭代器,这样就不用关心菜单是使用 ArrayList 还是数组记录菜单项了。

(1)创建菜单项

/**
* 菜单项
*/
public class MenuItem { String name;
double price; public MenuItem(String name, double price) {
this.name = name;
this.price = price;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public double getPrice() {
return price;
} public void setPrice(double price) {
this.price = price;
}
}

(2)创建迭代器接口

/**
* 迭代器接口
*/
public interface Iterator { /**
* 是否有下一个元素
*/
public boolean hasNext(); /**
* 获取下一个元素
*/
public Object next();
}

(3)创建具体的菜单迭代器

/**
* 煎饼屋菜单迭代器
*/
public class PancakeHouseMenuIterator implements Iterator { /**
* 列表形式的菜单项
*/
public ArrayList<MenuItem> menuItems;
int position = 0; public PancakeHouseMenuIterator(ArrayList<MenuItem> items) {
this.menuItems = items;
} @Override
public boolean hasNext() {
if (position < menuItems.size()) {
return true;
}
return false;
} @Override
public Object next() {
if (!this.hasNext()) {
return null;
}
MenuItem item = menuItems.get(position);
position = position + 1;
return item;
}
}
/**
* 餐厅菜单迭代器
*/
public class DinerMenuIterator implements Iterator { /**
* 数组形式的菜单项
*/
public MenuItem[] menuItems;
int position = 0; public DinerMenuIterator(MenuItem[] items) {
this.menuItems = items;
} @Override
public boolean hasNext() {
if (position < menuItems.length) {
return true;
}
return false;
} @Override
public Object next() {
if (!this.hasNext()) {
return null;
}
MenuItem item = menuItems[position];
position = position + 1;
return item;
}
}

(4)创建菜单接口

/**
* 菜单接口
*/
public interface Menu { /**
* 创建迭代器
*/
public Iterator createIterator();
}

(5)创建具体的菜单

/**
* 煎饼屋菜单
*/
public class PancakeHouseMenu implements Menu { public ArrayList<MenuItem> menuItems; public PancakeHouseMenu() {
menuItems = new ArrayList<MenuItem>();
menuItems.add(new MenuItem("Regular Pancake Breakfast", 2.99));
menuItems.add(new MenuItem("Blueberry Pancakes", 3.49));
menuItems.add(new MenuItem("Waffles", 3.59));
} @Override
public Iterator createIterator() {
return new PancakeHouseMenuIterator(menuItems);
}
}
/**
* 餐厅菜单
*/
public class DinerMenu implements Menu { public MenuItem[] menuItems; public DinerMenu() {
menuItems = new MenuItem[3];
menuItems[0] = new MenuItem("BLT", 2.99);
menuItems[1] = new MenuItem("Soup of the day", 3.29);
menuItems[2] = new MenuItem("Hotdog", 3.05);
} @Override
public Iterator createIterator() {
return new DinerMenuIterator(menuItems);
}
}

(6)创建女招待

/**
* 女招待
*/
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");
System.out.println("BREAKFASE:");
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() + ", " + menuItem.getPrice());
}
}
}

(7)使用女招待打印菜单

public class Test {

    public static void main(String[] args) {
// 菜单
Menu pancakeHouseMenu = new PancakeHouseMenu();
Menu dinerMenu = new DinerMenu();
// 女招待
Waitress waitress = new Waitress(pancakeHouseMenu, dinerMenu);
// 打印菜单
waitress.printMenu();
}
}

《Head First 设计模式》:迭代器模式的更多相关文章

  1. JavaScript设计模式与开发实践 - 策略模式

    引言 本文摘自<JavaScript设计模式与开发实践> 在现实中,很多时候也有多种途径到达同一个目的地.比如我们要去某个地方旅游,可以根据具体的实际情况来选择出行的线路. 如果没有时间但 ...

  2. 《JavaScript设计模式与开发实践》整理

    最近在研读一本书<JavaScript设计模式与开发实践>,进阶用的. 一.高阶函数 高阶函数是指至少满足下列条件之一的函数. 1. 函数可以作为参数被传递. 2. 函数可以作为返回值输出 ...

  3. 《javascript设计模式与开发实践》--- (单一职责原则)

    看的这本书叫<JavaScript设计模式与开发实践> 先规划一下看书的顺序,基础知识我已经大概的浏览了一遍了,没有留下笔记,以后有时间还会补上.本来打算顺着看的.但是我感觉我很难短时间内 ...

  4. 《Javascript设计模式与开发实践》--读书笔记

    第2章 this call apply bind()方法创建一个新的函数,在bind()被调用时,这个新函数的this被bind的第一个参数指定,其余的参数将作为新函数的参数供调用时使用. bind( ...

  5. JavaScript设计模式与开发实践 - 观察者模式

    概述 观察者模式又叫发布 - 订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个目标对象(为了方便理解,以下将观察者对象叫做订阅者,将目标对象叫做 ...

  6. JavaScript设计模式与开发实践 - 单例模式

    引言 本文摘自<JavaScript设计模式与开发实践> 在传统开发工程师眼里,单例就是保证一个类只有一个实例,实现的方法一般是先判断实例存在与否,如果存在直接返回,如果不存在就创建了再返 ...

  7. 《JavaScript设计模式与开发实践》读书笔记-基础知识

    笔记内容多摘录自<JavaScript设计模式与开发实践>(曾探著),侵删. 面向对象的JavaScript 1. 动态需要类型和鸭子类型 鸭子类型 如果它走起路来像鸭子,叫起来也是鸭子, ...

  8. JavaScript设计模式与开发实践——读书笔记1.高阶函数(上)

    说来惭愧,4个多月未更新了.4月份以后就开始忙起来了,论文.毕设.毕业旅行等七七八八的事情占据了很多时间,毕业之后开始忙碌的工作,这期间一直想写博客,但是一直没能静下心写.这段时间在看<Java ...

  9. Javascript设计模式之我见:迭代器模式

    大家好!本文介绍迭代器模式及其在Javascript中的应用. 模式介绍 定义 提供一种方法顺序一个聚合对象中各个元素,而又不暴露该对象内部表示. 类图及说明 Iterator抽象迭代器 抽象迭代器负 ...

  10. javascript设计模式与开发实践阅读笔记(7)——迭代器模式

    迭代器模式:指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示. 迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺 ...

随机推荐

  1. XSS基础笔记 from 《Web安全攻防 渗透测试实战指南》

    XSS漏洞介绍 跨站脚本(Cross Site Scripting, 简称为XSS或跨站脚本或跨站脚本攻击)是一种针对网站应用程序的安全漏洞攻击技术,是代码注入的一种.它允许恶意用户将代码注入网页,其 ...

  2. Python练习题 002:奖金计算

    [Python练习题 002]企业发放的奖金根据利润提成.利润(I)低于或等于10万元时,奖金可提10%:利润高于10万元,低于20万元时,低于10万元的部分按10%提成,高于10万元的部分,可可提成 ...

  3. 为自己的网页博客添加L2Dwidget.js看板娘

    如果是博客园,直接在设置-->页脚 HTML 代码,加上下面代码: 1 <!-- L2Dwidget.js L2D网页动画人物 --> 2 <script src=" ...

  4. 达梦数据库_DM8配置MPP主备

    为了提高MPP系统可靠性,克服由于单节点故障导致整个系统不能继续正常工作,DM 在普通的MPP系统基础上,引入主备守护机制,将MPP节点作为主库节点,增加备库作为备份节点,必要时可切换为主库代替故障节 ...

  5. 每日一题 LeetCode 486. 预测赢家 【递推】【前缀和】【动态规划】

    题目链接 https://leetcode-cn.com/problems/predict-the-winner/ 题目说明 题解 主要方法:递推:动态规划:前缀和 解释说明: 求前缀和 pre_nu ...

  6. 多测师讲解rf--定位元素--高级讲师肖sir

    注意点: 注意点: rfbug:rf 点击勾选一个运行就运行两个出现用例执行 注释快捷键: 改字体大小: 快捷键:显示关键字信息 (ctrl+鼠标悬浮) 注解不能空格在注解 未保存提示 定位方法 : ...

  7. 多测师讲解html _链接标签004_高级讲师肖sir

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>链 ...

  8. Oracle函数总结

    <Trunc()> 描       述(实际应用):截取小数或者日期整数 简      介:https://baike.baidu.com/item/trunc/9657216?fr=al ...

  9. 初识 MongoDB 和 .NET Core 入门

    昨天搭建完毕 MongoDB 集群 后,开始计划了解 MongoDB ,并引入使用场景,这里介绍一下学习过程中的一些笔记,帮助读者快速了解 MongoDB 并使用 C# 对其进行编码. 浅入 Mong ...

  10. 转 Swoole】用swoole简单实现MySQL连接池

    MySQL连接池 在传统的网站开发中,比如LNMP模式,由Nginx的master进程接收请求然后分给多个worker进程,每个worker进程再链接php-fpm的master进程,php-fpm再 ...