《HeadFirst设计模式(第二版)》第九章代码——迭代器模式
情景:
一家早餐店和一家午餐点准备合并在一起,两家的点菜的菜单实现方式如下:
首先,他们的菜单选项都基于同一个类:
菜单选项类
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<MenuItem> menuItems;public PancakeHouseMenu(){this.menuItems = new ArrayList<MenuItem>();addItem("K&B's Pancake Breakfast","Pancake with scrambled eggs and toast",true,2.99);addItem("Regular Pancake Breakfast","Pancake with fired eggs, sausage",false,2.99);addItem("BlueBerry Pancake","Pancake made with fresh blueberries",true,3.49);addItem("Waffles","Waffles with your choice of blueberries of strawberries",true,3.59);}public void addItem(String name,String description,boolean vegetarian,double price){MenuItem menuItem = new MenuItem(name,description,vegetarian,price);this.menuItems.add(menuItem);}public List<MenuItem> getMenuItems(){return this.menuItems;}
}
午餐店初始菜单:
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<MenuItem> breakfastItems = pancakeHouseMenu.getMenuItems();DinerMenu dinerMenu = new DinerMenu();MenuItem[] lunchItems = dinerMenu.getMenuItems();for(int i= 0;i<breakfastItems.size();++i){MenuItem menuItem = breakfastItems.get(i);System.out.println(menuItem.getName()+" ");System.out.println(menuItem.getPrice()+" ");System.out.println(menuItem.getDescription()+" ");}for(int i = 0;i<lunchItems.length;++i){MenuItem menuItem = lunchItems[i];System.out.println(menuItem.getName()+" ");System.out.println(menuItem.getPrice()+" ");System.out.println(menuItem.getDescription()+" ");}}public static void main(String[] args) {Waitress waitress = new Waitress();waitress.printMenu();}
}
由此可见:服务员类和两个菜单类直接接触,既违反封装原理,还违背了面向接口编码的原理,同时极其不利于维护。
迭代器模式
这时可以采用迭代器模式:在两个菜单和服务员之间加入一个迭代器(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<MenuItem> items;int position = 0;public PancakeHouseIterator(List<MenuItem> items){this.items = items;}@Overridepublic MenuItem next() {MenuItem menuItem = items.get(position);position++;return menuItem;}@Overridepublic 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;}@Overridepublic MenuItem next() {MenuItem menuItem = items[position];position++;return menuItem;}@Overridepublic 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();}
}
使用JAVA自带的迭代器
因为早餐菜单使用了ArrayList,它有iterator()方法返回一个迭代器(所以这里可以删除掉它的自定义迭代器),然而午餐菜单是用数组实现的,没有这个方法,所以午餐类还是需要使用自定义的迭代器(“继承”于java的迭代器)。
修改早餐类:
添加头文件:
import java.util.Iterator;
然后修改方法:
public Iterator<MenuItem> createIterator(){return menuItems.iterator();}
修改午餐迭代器类:
package Chapter9_IteratorPattern.JavaIterator;
import java.util.Iterator;/*** @Author 竹心* @Date 2023/8/17**/public class DinerMenuIterator implements Iterator<MenuItem>{MenuItem[] items;int position = 0;public DinerMenuIterator(MenuItem[] items){this.items = items;}@Overridepublic MenuItem next() {MenuItem menuItem = items[position];position++;return menuItem;}@Overridepublic boolean hasNext() {if(position >= items.length || items[position] == null){return false;}else{return true;}}@Overridepublic void remove() {//java自带的迭代器是由remove()方法的,所以这里必须要实现throw new UnsupportedOperationException("you can not remove it!");}
}
添加Menu接口:
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()+" ");}}
}
情景扩展1
好了,现在又有一家咖啡店并入餐厅,并在晚上提供服务,这家咖啡店也有它独特的菜单实现方式:使用哈希表!接下来要将它加入迭代器的使用中(这里将其称为晚餐菜单):
使用JAVA自带迭代器的晚餐菜单:
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<String, MenuItem> menuItems = new HashMap<String, MenuItem>();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<String, MenuItem> getItems() {
// return menuItems;
// }public Iterator<MenuItem> 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<Menu> menus;public Waitress(ArrayList<Menu> menus) {this.menus = menus;}public void printMenu() {Iterator<?> menuIterator = menus.iterator();while(menuIterator.hasNext()) {Menu menu = (Menu)menuIterator.next();printMenu(menu.createIterator());}}void printMenu(Iterator<?> iterator) {while (iterator.hasNext()) {MenuItem menuItem = (MenuItem)iterator.next();System.out.print(menuItem.getName() + ", ");System.out.print(menuItem.getPrice() + " -- ");System.out.println(menuItem.getDescription());}}
}
情景扩展2
现在问题来了,如果菜单中存在子菜单,那么又该如何实现呢?
很明显上面的方法已经不适用了,重写菜单代码才行。
这里就引出了组合模式:
《HeadFirst设计模式(第二版)》第九章代码——组合模式_轩下小酌的博客-CSDN博客
相关文章:
《HeadFirst设计模式(第二版)》第九章代码——迭代器模式
情景: 一家早餐店和一家午餐点准备合并在一起,两家的点菜的菜单实现方式如下: 首先,他们的菜单选项都基于同一个类: 菜单选项类 package Chapter9_IteratorPattern.Origin;/*** Author 竹心* Date 2023/8/17**/public class Men…...
Electron入门,项目启动。
electron 简单介绍: 实现:HTML/CSS/JS桌面程序,搭建跨平台桌面应用。 electron 官方文档: [https://electronjs.org/docs] 本文是基于以下2篇文章且自行实践过的,可行性真实有效。 文章1: https://www.cnbl…...
深入理解索引B+树的基本原理
目录 1. 引言 2. 为什么要使用索引? 3. 索引的概述 4. 索引的优点是什么? 4.1 降低数据库的IO成本,提高数据查找效率 4.2 保证数据库每一行数据的唯一性 4.3 加速表与表之间的连接 4.4 减少查询中分组与排序的执行时间 5. 索引的缺点…...
vue3 简易用对话框实现点击头像放大查看
设置头像悬停手势 img:hover{cursor: pointer;}效果: 编写对话框 <el-dialog class"bigAvatar"style"border-radius: 4px;"v-model"deleteDialogVisible"title"查看头像"top"5px"><div><img src&…...
opencv 矩阵运算
1.矩阵乘(*) Mat mat1 Mat::ones(2,3,CV_32FC1);Mat mat2 Mat::ones(3,2,CV_32FC1);Mat mat3 mat1 * mat2; //矩阵乘 结果 2.元素乘法或者除法(mul) Mat m Mat::ones(2, 3, CV_32FC1);m.at<float>(0, 1) 3;m.at…...
第四章 字符串part01
344.反转字符串 public void reverseString(char[] s) {int len s.length;int left 0;int right len-1;while (left < right){char tmp s[right];s[right] s[left];s[left] tmp;left;right--;} }反转字符串II 注意String不可变,因此可使用char数组或者St…...
Python3内置函数大全
吐血整理 Python3内置函数大全 1.abs()函数2.all()函数3.any()函数4.ascii()函数5.bin()函数6.bool()函数7.bytes()函数8.challable()函数9.chr()函数10.classmethod()函数11.complex()函数12.complie()函数13.delattr()函数14.dict()函数15.dir()函数16.divmod()函数17.enumer…...
什么是“新型基础设施”?建设重点是什么?
一是信息基础设施。主要是指基于新一代信息技术演化生成的基础设施,比如,以5G、物联网、工业互联网、卫星互联网为代表的通信网络基础设施,以人工智能、云计算、区块链等为代表的新技术基础设施,以数据中心、智能计算中心为代表的…...
混杂接口模式---vlan
策略在两个地方可以用--1、重发布 2、bgp邻居 2、二层可以干的,三层也可以干 3、未知单播:交换机的MAC地址表的记录保留时间是5分钟,电脑的ARP表的记录保留时间是2小时 4、route recursive-lookup tunnel 华为默认对于bgp学习来的路由不开启标…...
Greenplum多级分区表添加分区报错ERROR: no partitions specified at depth 2
一般来说,我们二级分区表都会使用模版,如果没有使用模版特性,那么就会报ERROR: no partitions specified at depth 2类似的错误。因为没有模版,必须要显式指定分区。 当然我们在建表的时候,如果没有指定,那…...
EV PV AC SPI CPI TCPI
SPI EV / PV CPI EV / ACCPI 1.25 SPI 0.8 PV 10 000 BAC 100 000EV PV * SPI 10 000 * 0.8 8000 AC EV / CPI 8000 / 1.25 6400TCPI (BAC - EV) / (BAC -AC) (100 000 - 8 000) / (100 000 - 6 400) 92 000 / 93 600 0.98290598...
【电商领域】Axure在线购物商城小程序原型图,品牌自营垂直电商APP原型
作品概况 页面数量:共 60 页 兼容软件:Axure RP 9/10,不支持低版本 应用领域:网上商城、品牌自营商城、商城模块插件 作品申明:页面内容仅用于功能演示,无实际功能 作品特色 本作品为品牌自营网上商城…...
Cpp基础Ⅰ之编译、链接
1 C是如何工作的 工具:Visual Studio 1.1 预处理语句 在.cpp源文件中,所有#字符开头的语句为预处理语句 例如在下面的 Hello World 程序中 #include<iostream>int main() {std::cout <"Hello World!"<std::endl;std::cin.get…...
用户新增预测(Datawhale机器学习AI夏令营第三期)
文章目录 简介任务1:跑通Baseline实操并回答下面问题:如果将submit.csv提交到讯飞比赛页面,会有多少的分数?代码中如何对udmp进行了人工的onehot? 任务2.1:数据分析与可视化编写代码回答下面的问题…...
RGOS日常管理操作
RGOS日常管理操作 一、前言二、RGOS平台概述2.1、锐捷设备的常用登陆方式2.2、使用Console登入2.3、Telnet远程管理2.4、SSH远程管理2.5、登陆软件:SecureCRT 三、CLI命令行操作3.1、CLI命令行基础3.2、CLI模式3.3、CLI模式互换3.4、命令行特性3.4.1、分屏显示3.4.2…...
阿里云使用WordPress搭建个人博客
手把手教你使用阿里云服务器搭建个人博客 一、免费创建服务器实例 1.1 点击试用 点击试用会需要你创建服务器实例,直接选择默认的操作系统即可,点击下一步 1.2 修改服务器账号密码 二、创建云数据库实例 2.1 免费获取云数据库使用 2.2 实例列表页 在…...
供应链安全和第三方风险管理:讨论如何应对供应链中的安全风险,以及评估和管理第三方合作伙伴可能带来的威胁
第一章:引言 在当今数字化时代,供应链的安全性越来越受到重视。企业的成功不仅仅依赖于产品和服务的质量,还取决于供应链中的安全性。然而,随着供应链越来越复杂,第三方合作伙伴的参与也带来了一系列安全风险。本文将…...
《Java极简设计模式》第04章:建造者模式(Builder)
作者:冰河 星球:http://m6z.cn/6aeFbs 博客:https://binghe.gitcode.host 文章汇总:https://binghe.gitcode.host/md/all/all.html 源码地址:https://github.com/binghe001/java-simple-design-patterns/tree/master/j…...
Go download
https://go.dev/dl/https://golang.google.cn/dl/...
2023年Java核心技术面试第四篇(篇篇万字精讲)
目录 八. 对比Vector,ArrayList, LinkedList有何区别? 8.1 典型回答 8.1.1 Vector: 8.1.2 ArrayList : 8.1.3 LinkedList 8.2 考察点分析: 8.2.1 不同容器类型适合的场景 八. 对比Vector,ArrayList, Linke…...
Uvicorn与Scaleway Serverless Functions:无服务器Python应用部署终极指南
Uvicorn与Scaleway Serverless Functions:无服务器Python应用部署终极指南 【免费下载链接】uvicorn An ASGI web server, for Python. 🦄 项目地址: https://gitcode.com/GitHub_Trending/uv/uvicorn Uvicorn作为Python生态中最快、最现代的ASGI…...
付费墙绕过工具深度解析:技术原理与合规使用指南
付费墙绕过工具深度解析:技术原理与合规使用指南 【免费下载链接】bypass-paywalls-chrome-clean 项目地址: https://gitcode.com/GitHub_Trending/by/bypass-paywalls-chrome-clean 在数字内容付费模式日益普及的今天,如何在尊重知识产权的前提…...
文科生被AI大厂疯抢,月薪3万起,这条热搜,你真的看懂了吗?
最近有个话题悄悄冲上热搜,看得不少人心里一热——#AI大厂月薪3万疯抢文科生#。 事情起因是360创始人周鸿祎在一次采访里说了个挺颠覆的观点:“随着AI技术的发展,文科生将比理科生更吃香。”截图来源微博(如侵删) 他给…...
React篇——第一章 React的基础知识(上篇)
目录 1. React简介 1.1 什么是React 1.2 React的核心优势 组件化开发 虚拟DOM 丰富的生态系统 跨平台支持 1.3 React的市场地位 2. 开发环境搭建 2.1 使用create-react-app创建项目 2.2 其他创建React项目的方式 3. JSX基础 3.1 什么是JSX 3.2 JSX的优势 3.3 JS…...
告别振动噪音:用DRV8825模块的细分功能,让你的3D打印机或CNC雕刻机运行更安静平稳
静音革命:DRV8825微步进技术在3D打印与CNC中的实战应用 当你的3D打印机在深夜工作时发出刺耳的嗡嗡声,或是CNC雕刻机在低速运行时产生令人不适的振动,这不仅影响工作环境,更会直接反映在成品质量上——那些本应光滑的表面出现的细…...
OpenClaw+nanobot镜像:3步配置QQ聊天机器人触发AI任务
OpenClawnanobot镜像:3步配置QQ聊天机器人触发AI任务 1. 为什么选择OpenClawnanobot组合? 去年冬天,当我第一次尝试用QQ机器人自动处理群消息时,经历了漫长的环境配置地狱。直到发现星图平台的nanobot镜像,这个开箱即…...
TrollInstallerX终极指南:一键在iOS设备上安装TrollStore的完整教程
TrollInstallerX终极指南:一键在iOS设备上安装TrollStore的完整教程 【免费下载链接】TrollInstallerX A TrollStore installer for iOS 14.0 - 16.6.1 项目地址: https://gitcode.com/gh_mirrors/tr/TrollInstallerX 您是否一直在寻找一种简单可靠的方法&am…...
OpenClaw学术研究助手:Qwen3-32B驱动的论文摘要与笔记整理
OpenClaw学术研究助手:Qwen3-32B驱动的论文摘要与笔记整理 1. 为什么需要本地化的AI研究助手? 去年冬天,我在整理一个跨学科研究项目的文献时陷入了困境。手头堆积了200多篇PDF论文,每篇都需要提取核心观点、记录关键数据&#…...
PyTorch 2.8镜像实战案例:自媒体创作者批量生成短视频封面图工作流
PyTorch 2.8镜像实战案例:自媒体创作者批量生成短视频封面图工作流 1. 场景痛点与解决方案 短视频创作者每天面临的最大挑战之一,就是需要为每个视频制作吸引眼球的封面图。传统方式要么依赖设计师(成本高、周期长),…...
Anthropic Economic Index: AI对软件开发的影响 — 深度解读
原文: AI’s impact on software development 发布机构: Anthropic 解读日期: 2026年3月25日 一、研究背景与方法论 1.1 研究动机 软件开发工作虽然在现代经济中占比较小,但影响力巨大。过去两年,能够辅助甚至自动化大量编程工作的AI系统的引入&#x…...
