迭代器模式

意图

提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴漏该对象的内部表示

迭代器模式的诞生

【产品】:嘿,有一个好消息,咱们旗下的餐厅把月巴克的咖啡店吞并了!太棒了!年终奖稳了!

【开发】:Yeah!Yeah!Yeah!

【产品】:但是他们好像反应一个问题,月巴克的点餐系统好像不兼容我们的体系,怎么回事?不就是一个菜单吗?

【开发】:Oh!No!一定它们的 数据结构 不一样导致的,遍历出现了问题!

【产品】:那怎么办?BOSS,你们一起想想办法吧!

【开发】:老大,我们能不能把遍历方法抽取出来啊?我们遍历操作就可以不用考虑各种细节了,只需要管遍历类就好了。

【BOSS】:什么遍历类的,这叫 迭代器 好吗!其实JDK对于迭代器已经维护的很好了,但是咱们这业务也有一点特殊性,就按你说的办吧,办不好的话,刚才说的年终奖就没了。

【开发】:哦,好的(脸上笑嘻嘻,心里MMP)

HeadFirst 核心代码

自己整一个迭代器

定义迭代器持有者 非必须代码

/*** ******************************* description:  迭代器持有者* *******************************/
public interface MyContainer {MyIterator getIterator();
}

迭代器接口

/*** ******************************* description:  迭代器接口* *******************************/
public interface MyIterator {boolean hasNext();Object next();
}

迭代器工作类 食物菜单

public class FoodRepository implements MyContainer {String[] names = {"宫保鸡丁", "麻辣香锅", "油闷大虾"};@Overridepublic MyIterator getIterator() {return new NameIterator();}private class NameIterator implements MyIterator {private int index;@Overridepublic boolean hasNext() {return index < names.length;}@Overridepublic Object next() {return hasNext() ? names[index++] : null;}NameIterator() {index = 0;}}
}

迭代器工作类 咖啡菜单

public class CoffeeRepository implements MyContainer {List<String> names = Arrays.asList("雀巢咖啡", "黑糖玛奇朵", "半点寂寞");@Overridepublic MyIterator getIterator() {return new NameIterator();}private class NameIterator implements MyIterator {private int index;@Overridepublic boolean hasNext() {return index < names.size();}@Overridepublic Object next() {return hasNext() ? names.get(index++) : null;}NameIterator() {index = 0;}}
}

测试类 观察调用的表现形式

public class App {public static void main(String[] args){// 餐厅菜单FoodRepository food = new FoodRepository();MyIterator foodIterator = food.getIterator();while (foodIterator.hasNext()) {System.out.println("Food: -> " + foodIterator.next());}CodeUtils.spilt();// 咖啡菜单CoffeeRepository coffee = new CoffeeRepository();MyIterator coffeeIterator = coffee.getIterator();while (coffeeIterator.hasNext()) {System.out.println("Coffee: -> " + coffeeIterator.next());}}
}

JDK中的迭代

public class App {public static void main(String[] args){// JDKList<String> names = Arrays.asList("Han", "John", "Tomams");Iterator<String> iterable = names.iterator();while (iterable.hasNext()) {System.out.println("JDK Iterator: -> " + iterable.next());}CodeUtils.spilt();// JDKnames.forEach(s -> System.out.println("JDK forEach: -> " + s));}
}

因此对于业务上没有什么要求且常见的数据结构,我们不再需要自行定义迭代器

迭代器模式的设计思路:

  • Iterator 迭代器
  • Concretelterator 具体迭代器
  • Aggregate 集合
  • ConcreteAggregate 具体集合

简单来说,

  1. 我们需要明确集合的类型(数组,链表,Map,树结构或者普通List)
  2. 我们需要定义迭代器的行为,是否有下一个(遍历完成),取值,移除等等
  3. 遍历的行为或者算法在具体的迭代器中实现,根据不同的数据结构和业务要求完成编码,实现访问一致,但细节不同的效果

如果看着有点模棱两可,就看完本文后,访问专题设计模式开源项目,里面有具体的代码示例,链接在最下面

遵循的设计原则

  • 单一职责原则

说明:迭代器类在设计中仅仅包含集合迭代的作用,它是把原本数据结构中的遍历抽取出来,达到 高内聚 的效果。

所谓高内聚:当一个模块或一个类被设计成只支持一组相关功能时,我们说它具有 高内聚 的特征。

什么场景适合使用

  • 访问一个聚合对象的内容而无需暴漏它的内部表示
  • 支持对聚合对象的多种遍历
  • 为遍历不同的聚合结构提供一个统一的接口

Code/生活中的实际应用

举一个不是很恰当的例子,我们都用自动贩卖机买过水,付钱之后它会自动滚出来,大家有没有想过它是怎么实现这个效果的呢?它支持瓶装的,罐装的,甚至还支持袋装的,方便面,口红等等五花八门的产品,它的内部结构可能都各不相同,但是最终的表现效果就是我们直接从出口处拿即可,这是不是迭代器模式的一种体现呢?

迭代器模式UML图

组合模式

意图

将对象组合成树形结构以表示 “部分-整体” 的层次结构,Composite使得用户对单个对象和组合对象的使用具有一致性

说人话:想想Java里的File类

组合模式的误区

组合模式 不是 一堆模式的组合!

组合模式的诞生

【开发】:老大,我在写菜单类的时候感觉好痛苦啊!

【BOSS】:怎么了?

【开发】:菜单有真正的菜品,还有父级菜单啊,它们俩得维护两套逻辑,混在一起好难受!

【BOSS】:你在操作文件的时候怎么不觉得难受?你咋不动动脑子想着抽象一下啊!

【开发】:对啊!我去改代码!

HeadFirst 核心代码

定义抽象行为

/*** ******************************* description:  定义抽象行为* *******************************/
public abstract class MenuComponent {public String name;/**** 添加*/public abstract void add(MenuComponent component) throws Exception;/**** 移除*/public abstract void remove(MenuComponent component) throws Exception;/**** 获取菜单名*/public abstract String getName();/**** 获取子菜单*/public abstract MenuComponent getChild(int i) throws Exception;/**** 打印菜单*/public abstract void print();
}

实现 “整体”

public class Menu extends MenuComponent{List<MenuComponent> menuComponents = new ArrayList<>();public Menu(String name) {this.name = name;}@Overridepublic void add(MenuComponent component) {this.menuComponents.add(component);}@Overridepublic void remove(MenuComponent component) {this.menuComponents.remove(component);}@Overridepublic String getName() {return this.name;}@Overridepublic MenuComponent getChild(int i) {return menuComponents.get(i);}@Overridepublic void print() {System.out.println("当前菜单项: " + getName());for (MenuComponent component : menuComponents) {component.print();}}
}

实现 "部分"

public class MentItem extends MenuComponent{public MentItem(String name) {this.name = name;}@Overridepublic void add(MenuComponent component) throws Exception {throw new Exception("无法添加");}@Overridepublic void remove(MenuComponent component) throws Exception {throw new Exception("无法移除");}@Overridepublic String getName() {return this.name;}@Overridepublic MenuComponent getChild(int i) throws Exception {throw new Exception("无子节点");}@Overridepublic void print() {System.out.println("    食物名: " + getName());}
}

测试类

public class App {/**** 推荐代码阅读顺序:** @see MenuComponent* @see Menu* @see MentItem*/public static void main(String[] args) {Menu meat = new Menu("炒菜类");MentItem item1 = new MentItem("宫保鸡丁");MentItem item2 = new MentItem("剁椒鸡蛋");MentItem item3 = new MentItem("鱼香肉丝");Menu vegetable = new Menu("素食");MentItem v1 = new MentItem("酸辣土豆丝");MentItem v2 = new MentItem("爆炒包菜");meat.add(item1);meat.add(item2);meat.add(item3);vegetable.add(v1);vegetable.add(v2);meat.add(vegetable);meat.print();}
}/**** 输出内容:** 当前菜单项: 炒菜类*     食物名: 宫保鸡丁*     食物名: 剁椒鸡蛋*     食物名: 鱼香肉丝* 当前菜单项: 素食*     食物名: 酸辣土豆丝*     食物名: 爆炒包菜*/

组合模式的设计思路:

  • Component 为组合的对象声明接口或抽象类
  • Leaf 叶子节点(最小单元)
  • Composite 组合节点(即还有子节点的节点)
  • Client 客户端,调用方

简单来说,

  1. 当我们需要树形结构时,抽象叶子节点和组合节点(有子节点的节点)的共同行为
  2. 让两者实现同一个接口

如果看着有点模棱两可,就看完本文后,访问专题设计模式开源项目,里面有具体的代码示例,链接在最下面

什么场景适合使用

  • 需要表示对象的部分-整体层次结构
  • 希望用户忽略组合对象与单个对象的不同,用户统一地使用组合结构中所有对象

Code/生活中的实际应用

依然是一个不太恰当的例子,我们在操作文件和文件夹的时候,都有其移动,复制,重命名,查看文件大小等等功能,对于Java来说,它的底层实现是有一个 是否是文件夹的方法来区分,但实际上这也是组合模式的根本思想,即对于表示 部分 的对象,和 整体 的对象,拥有统一的操作行为

组合模式的UML图

总结

  • 迭代器模式:该模式在JDK中已经封装的非常好,我们其实不太需要再自行处理,不过在处理特殊数据结构时这种统一操作的思想仍然值得借鉴
  • 组合模式:组合模式仅在需要树形结构的场景下可发挥巨大的作用,同样的,它规范不同类型对象的行为,统一操作的思想,值得我们借鉴

相关代码链接

GitHub地址

  • 兼顾了《HeadFirst》以及《GOF》两本经典书籍中的案例
  • 提供了友好的阅读指导

【一起学系列】之迭代器组合:虽然有点用不上啦相关推荐

  1. 跟着小马哥学系列之 Spring AOP(Pointcut 组件详解)

    学好路更宽,钱多少加班. --小马哥 版本修订 2021.5.19:去除目录 2021.5.21:引用 Spring 官方 Pointcut 概念,修改 Pointcut 功能表述 简介 大家好,我是 ...

  2. 视频教程-Java工程师必学系列课程之4--《Java Swing》视频课程-Java

    Java工程师必学系列课程之4--<Java Swing>视频课程 某知名科技公司技术总监,10年以上大型J2EE项目的实战研发经验,参与并主持开发"内蒙古电力集团考试系统&qu ...

  3. 互联网大脑的情绪,智商和梦境-互联网神经学系列第四篇

    这是互联网神经学系列的第四篇文章"互联网大脑的情绪.智商和梦境,互联网神经心理学" 1.互联网神经心理学的提出 我们在互联网神经学系列的第三篇文章中详细介绍了互联网大脑的架构和运行 ...

  4. 互联网神经学系列第五篇:研究大脑中的谷歌,脸书和华为思科路由,脑互联网生理学

    本文是互联网神经学系列第五篇-"大脑中的类互联网应用和结构,脑互联网生理学" 一.人类大脑研究的困境 大脑的秘密一直是科学皇冠上最明亮的宝石之一,但在两千年前,人们确连它的重要意义 ...

  5. 一木.溪桥学Python-11:迭代器、生成器、面象对象class MyClass:、self 参数、 __init__() 方法、__str__() 方法

    一木.溪桥 在Logic Education跟Amy学Python 逻辑教育 :https://logicedu.ke.qq.com 12期:Python基础课 一木.溪桥学Python-11:迭代器 ...

  6. Java反射机制大神必学系列之 ,高级与低级的差别在哪里?

    Java反射机制大神必学系列之 ,高级与低级的差别在哪里? java学习爱好者 2019-05-20 19:08 前言 今天介绍下Java的反射机制,以前我们获取一个类的实例都是使用new一个实例出来 ...

  7. java私塾 java篇_Java私塾跟我学系列——JAVA篇 五、

    五:Java如何做到让机器理解我们想要做的东西 用一个图来描述这个过程会比较容易理解: 1:编写代码 首先把我们想要计算机做的事情,通过Java表达出来,写成Java文件,这个过程就是 编写代码的过程 ...

  8. [js高手之路] es6系列教程 - 迭代器与生成器详解

    什么是迭代器? 迭代器是一种特殊对象,这种对象具有以下特点: 1,所有对象都有一个next方法 2,每次调用next方法,都会返回一个对象,该对象包含两个属性,一个是value, 表示下一个将要返回的 ...

  9. 今年春季清华大学雨课堂主讲嘉宾邹晓辉讲授了融智学系列公益课:

    今年春季清华大学雨课堂主讲嘉宾邹晓辉讲授了融智学系列公益课: 部分录屏回访可从头条号西瓜视频可见推荐数和观看数的统计数字:部分在B网可直接观看回放.俗话说:教学相长.大学理念则告诉我们:教学.研究和社 ...

  10. Docker重学系列之高级网络篇

    Docker重学系列之高级网络篇 高级网络配置 说明 veth-pair技术 网络小结 Docker 网络相关的命令列表 容器访问控制 容器访问外部网络 容器之间访问 访问所有端口 访问指定端口 映射 ...

最新文章

  1. 像优秀的SQL程序员一样思考
  2. DELL备份恢复系统的小工具 Dell DataSafe Local Backup
  3. @成都的Coder ,一起探讨终端架构持续演进
  4. msg批量转html,SysTools MSG Converter(MSG格式转换器)
  5. 【机器学习】传统目标检测算法之级联分类器Cascade
  6. 固执己见的框架(例如Spring Boot)的危险。 求知代码反转
  7. C++ 中 new 操作符内幕:new operator、operator new、placement new
  8. Android 异步加载神器Loader全解析
  9. Uber宣布停止无人卡车项目,研发重心将转向无人小汽车
  10. 利用dropbox来Host你的silverlight应用
  11. 搜索引擎选择: Elasticsearch与Solr(转载)
  12. 最新北风网 web全栈视频教程
  13. EDA课程设计-拔河游戏A设计
  14. python自带的库有哪些_吐血整理!140种Python标准库、第三方库和外部工具都有了...
  15. 方向余弦阵,欧拉角,四元数
  16. 二项分布 (Binomial Distribution)
  17. timestamp与datetime使用
  18. 企业快速寄件打单教程
  19. swoole基础教程-2.入门
  20. 一心多用多线程-线程的生命周期

热门文章

  1. ESP32C3 CORE+PIO+lvgl显示
  2. matlab 循环和判断语句,matlab中循环语句与for循环
  3. Linux 下恢复误删文件
  4. 2021年N1叉车司机找解析及N1叉车司机试题及解析
  5. 网络版库存管理系统如何共享库存信息
  6. 证书与签名(二):数字签名流程与签名认证流程
  7. 笔记本计算机管理没有键盘,如何禁用笔记本键盘输入?怎么关闭笔记本键盘
  8. 12 款适用于开发人员的最佳 Web 开发软件
  9. 用Python进行web开发需要学习什么?
  10. java表达upll导包在哪_用java实现http断点续传.mht 源代码在线查看 - 自己平时从网上搜集的http协议解析文档 资源下载 虫虫电子下载站...