本文首发于cdream的个人博客,点击获得更好的阅读体验!

欢迎转载,转载请注明出处。

本文主要讲述迭代器模式,并使用遍历不同数据结构的王者荣耀和英雄联盟英雄作为例子帮助大家理解,最后附上阿离美图一张!

一、概述

迭代器模式(Iterator pattern):提供一种方法顺序访问一个聚合对象中的各个元素,而又不用暴露聚合底层的实现。

迭代器模式比较常见的设计模式,对于熟悉java集合的我们来说,会经常用到迭代器。当我们需要写一个方法来遍历集合,又不想针对不同的集合实现不同的方法,就可以使用迭代器来完成。

迭代器模式主要解决两个问题
1.聚集元素在访问和遍历时,不必要暴露底层数据结构(without exposing its representation)
2.当为一个新的聚集定义遍历操作时,不需要改变接口

二、结构

UML图:

主要角色:

聚合的接口(Aggregate):提供一个共同的接口,给所有的聚合使用,将客户代码从聚合的实现中解耦。

聚合的具体实现(ConcreateAggregate):这个具体实现会持有一个对象的集合,并实现createIterator()方法,通过这个方法可以返回一个对象的集合的迭代器。

迭代器接口(Iterator):这是一个迭代器接口,我们可以在里面定义一些方法,利用这些方法可以在集合元素之间游走。可以使用java自带的java.util.Iterator,也可以根据我们自己需要来定义一个Iterator。

迭代器具体实现(ConcreteIterator):由具体聚合提供一个工厂方法来实现具体迭代器,这个迭代器负责管理目前遍历的位置。

三、输出所有王者荣耀和英雄联盟的英雄信息

源代码

假设当前有这样一个需求,我们需要一个小助手,可以同时向用户展示王者荣耀和英雄联盟中的英雄信息,但是两款游戏维护英雄使用数据结构不同,一个数组,现在我们用迭代器来完成这个功能

定义英雄的实体类,包括姓名、性别、描述

public class Hero {private String name;private String sex;private String desc;public Hero(String name, String sex, String desc) {this.name = name;this.sex = sex;this.desc = desc;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public String getDesc() {return desc;}public void setDesc(String desc) {this.desc = desc;}@Overridepublic String toString() {return "Hero{" +"name='" + name + '\'' +", sex='" + sex + '\'' +", desc='" + desc + '\'' +'}';}
}

创建王者荣耀英雄类

public class HOKHeros {static final int MAX_HERO_COUNT = 10;int heroCount = 0;private Hero[] hokHeros = new Hero[MAX_HERO_COUNT];public HOKHeros() {Hero gsl = new Hero("公孙离", "妹子", "我觉得阿离是最漂亮的女英雄~");Hero lbqh = new Hero("鲁班七号", "男", "智商250");Hero wzt = new Hero("武则天", "女", "贼贵");hokHeros[0] = gsl;hokHeros[1] = lbqh;hokHeros[2] = wzt;this.heroCount = 3;}public Hero[] getHokHeros() {return hokHeros;}public void addHero(Hero hero) {if (heroCount >= MAX_HERO_COUNT) {System.out.println("已经不能放更多英雄了!");} else {hokHeros[this.heroCount] = hero;this.heroCount += 1;}}public Iterator<Hero> createIterator(){return new HOKHerosIterator(hokHeros);}
}

数组没有继承迭代器接口,所以我们自己实现一个!

public class HOKHerosIterator implements Iterator<Hero> {private int position = 0;private Hero[] heroes;public HOKHerosIterator(Hero[] heroes) {this.heroes = heroes;}@Overridepublic boolean hasNext() {if (heroes.length <= position || heroes[position] == null) {return false;}return true;}@Overridepublic Hero next() {Hero hero = heroes[position];position += 1;return hero;}}

创建英雄联盟英雄类

public class LOLHeros {private ArrayList<Hero> heroes;public LOLHeros() {heroes = new ArrayList<>();Hero gl = new Hero("盖伦", "男", "初始英雄");Hero rw = new Hero("锐雯", "女", "贼秀");Hero ys = new Hero("亚索", "男", "很厉害的样子");heroes.add(gl);heroes.add(rw);heroes.add(ys);}public ArrayList<Hero> getHeroes() {return heroes;}public void addHere(Hero hero){heroes.add(hero);}public Iterator<Hero> createIterator(){return heroes.iterator();}
}

小助手

public class HeroHelper {private Iterator iterator;public HeroHelper(Iterator iterator) {this.iterator = iterator;}public HeroHelper() {}public void showHeros() {while (iterator.hasNext()) {System.out.println(iterator.next());}}public void setIterator(Iterator iterator) {this.iterator = iterator;}
}

测试类

public class Test {public static void main(String[] args) {HOKHeros hokHeros = new HOKHeros();LOLHeros lolHeros = new LOLHeros();HeroHelper heroHelper = new HeroHelper();heroHelper.setIterator(hokHeros.createIterator());System.out.println("------");heroHelper.showHeros();heroHelper.setIterator(lolHeros.createIterator());heroHelper.showHeros();}
}
结果
Hero{name='公孙离', sex='妹子', desc='我觉得阿离是最漂亮的女英雄~'}
Hero{name='鲁班七号', sex='男', desc='智商250'}
Hero{name='武则天', sex='女', desc='贼贵'}
------
Hero{name='盖伦', sex='男', desc='初始英雄'}
Hero{name='锐雯', sex='女', desc='贼秀'}
Hero{name='亚索', sex='男', desc='很厉害的样子'}

从上面可以看出,迭代器需要两个核心方法hashNext(),next(),在java中还提供了remove()方法,根据需要我们可以自己实现迭代器,例如上文中,王者荣耀是用数组来储存英雄,我们手动实现了一个迭代器。

小助手并不需要清楚每款游戏在底层是如何储存英雄,但是只要可以创建迭代器,小助手就可以帮我们遍历英雄列表。

想象如果两款游戏没有实现迭代器接口,是不是就得在小助手里自己手写两个不同的for循环?

如果新加入了doto的英雄列表,它是用Hashtable来维护英雄列表的,我们现在就可以让它提供createItorator就可以,但若不使用迭代器,是不是就需要对小助手进行修改?

java中的集合

java的集合并未将迭代器单独创建一个类,而是将迭代器作为集合的内部类,这样迭代器可以自由操作集合内元素,即保证了聚合对象的封装又能实现迭代器模式。

public classArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable{private class Itr implements Iterator<E> {int cursor;       // index of next element to returnint lastRet = -1; // index of last element returned; -1 if no suchint expectedModCount = modCount;Itr() {}public boolean hasNext() {return cursor != size;}@SuppressWarnings("unchecked")public E next() {checkForComodification();int i = cursor;if (i >= size)throw new NoSuchElementException();Object[] elementData = ArrayList.this.elementData;if (i >= elementData.length)throw new ConcurrentModificationException();cursor = i + 1;return (E) elementData[lastRet = i];}public void remove() {if (lastRet < 0)throw new IllegalStateException();checkForComodification();try {ArrayList.this.remove(lastRet);cursor = lastRet;lastRet = -1;expectedModCount = modCount;} catch (IndexOutOfBoundsException ex) {throw new ConcurrentModificationException();}}@Override@SuppressWarnings("unchecked")public void forEachRemaining(Consumer<? super E> consumer) {Objects.requireNonNull(consumer);final int size = ArrayList.this.size;int i = cursor;if (i >= size) {return;}final Object[] elementData = ArrayList.this.elementData;if (i >= elementData.length) {throw new ConcurrentModificationException();}while (i != size && modCount == expectedModCount) {consumer.accept((E) elementData[i++]);}// update once at end of iteration to reduce heap write trafficcursor = i;lastRet = i - 1;checkForComodification();}final void checkForComodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException();}}
}

像这个ArrayList,内部主干是一个数组,但是别为对外提供获取该数组的方法,不过利用内部类依然实现了迭代器模式。

如果读过ArrayList源码,会注意modCount这个成员变量,用来记录ArrayList被修改次数(add,remove,set这类方法都会给modCount加1),在迭代器中checkForComodification(),用来实现fail-fast机制,当我们一个线程在使用迭代器遍历时,如果另一个线程对集合进行了修改,就会抛出异常。

四、优缺点

优点

  • 客户端不需要要了解具体底层实现,可以使用迭代器进行遍历
  • 符合开闭原则,当我们需要新添加一个聚合时,不需要对客户端进行修改,只需要使聚合实现迭代器接口就可以
  • 封装良好,客户端只需要迭代器就可以遍历,而不需要知道具体的迭代器算法

缺点

  • 对于简单的遍历,实现迭代器较为繁琐,用户可能更喜欢用for来进行遍历。

五、总结

迭代器模式在平时遍码过程中使用的频率并不高,但是了解迭代器却能加深我们对集合的了解。在java类中,除了Iterator外,Iterable、ListIterator也值得我们去了解~有兴趣的同学可以进行阅读。

掌握迭代器模式要把握住在不了解聚合底层实现的情况下进行遍历这个核心即可,一般来说,如果我们需要实现一个集合,就需要提供这个集合的迭代器。

另外,迭代器模式与工厂模式结合可以发挥巨大的威力!

希望本文对想要学习迭代器的小伙伴有所帮助,最后附离妹美图一张!


本文参考

  1. Head First 设计模式,Eric Freeman &Elisabeth Freeman with Kathy Sierra & Bert Bates
  2. Iterator pattern,wiki
  3. 《JAVA与模式》之迭代子模式

转载于:https://www.cnblogs.com/cdream-zs/p/10166700.html

设计模式——迭代器模式(遍历王者荣耀和英雄联盟英雄信息)相关推荐

  1. 设计模式之责任链模式在王者荣耀中的应用,学习到了!

    点击上方蓝色字体,选择"标星公众号" 优质文章,第一时间送达 关注公众号后台回复pay或mall获取实战项目资料+视频 作者:荣仔!最靓的仔! 来源:https://blog.cs ...

  2. 23种设计模式-迭代器模式《三国名将》

    对于许久不用的东西,容易忘记.百度许久,也未能找到自己所要. 从今日起,有些东西就记载下来,不仅方便自己,希望能帮到他人吧! 定义 提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部 ...

  3. java设计模式迭代器模式_迭代器设计模式示例

    java设计模式迭代器模式 本文是我们名为" Java设计模式 "的学院课程的一部分. 在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们. 您将了解模式 ...

  4. java设计模式迭代器模式_Java中的迭代器设计模式–示例教程

    java设计模式迭代器模式 迭代器模式是一种行为模式,它用于提供遍历一组对象的标准方式. Iterator模式在Java Collection Framework中得到了广泛使用,其中Iterator ...

  5. java设计模式迭代器模式_迭代器模式和Java

    java设计模式迭代器模式 大家好,在本文中,我们将检查Iterator Pattern . 我知道你们中许多人已经使用过一种设计模式,但是也许您没有意识到它是模式,或者不知道它的巨大价值. 根据&l ...

  6. java设计模式迭代器模式_Java中的迭代器设计模式

    java设计模式迭代器模式 Iterator design pattern in one of the behavioral pattern. Iterator pattern is used to ...

  7. 王者荣耀java,责任链模式在王者荣耀中的应用

    来源:https://blog.csdn.net/IT_charge 一.简述 在王者荣耀商城中,玩家可以参与夺宝抽奖.夺宝抽奖分两种,一种是积分抽奖,另一种是钻石抽奖:在平常,两种夺宝抽奖方式均可以 ...

  8. 责任链模式在王者荣耀中的应用,妙啊!

    点击上方"Java基基",选择"设为星标" 做积极的人,而不是积极废人! 每天 14:00 更新文章,每天掉亿点点头发... 源码精品专栏 原创 | Java ...

  9. 责任链模式在王者荣耀中的应用

    在王者荣耀商城中,玩家可以参与夺宝抽奖.夺宝抽奖分两种,一种是积分抽奖,另一种是钻石抽奖:在平常,两种夺宝抽奖方式均可以通过60钻石/积分抽奖一次,或者通过270钻石/积分连续抽奖5次:其中,当钻石夺 ...

最新文章

  1. KVM - 调整cpu内存、网卡
  2. 如何使用 SAP CDS view 中的 currency conversion 功能
  3. ASP.NET Core 实战:将 .NET Core 2.0 项目升级到 .NET Core 2.1
  4. 操作系统原理:进程 PV 操作如何计算?全网最全三种前驱图计算类型总结
  5. 多态——面向接口编程
  6. c语言名著摘抄——语法及实例
  7. 对平衡二叉搜索树Balance Binary Search Tree所有功能的实现的头文件
  8. 2021-04-26
  9. 新冠疫情分析(疫情数据爬取+数据分析+网页排版展示)
  10. ubuntu 安装osx 主题 转自linux公社
  11. 超简单的vue3.0,必看文档
  12. 利用MQTT协议与阿里云数据交互的python程序
  13. RGBA 编码为 YUV420SP【NEON】
  14. 手机如何借用笔记本网络上网
  15. 京东数据库泄露事件分析
  16. 李学江:B2B行业门户网站最终页标题设置方法
  17. python程序语言和机器人控制系统_机器人十大流行编程语言,机器人编程系统以及方法...
  18. 从0到1搭建一个简易的在线客服问答系统(附源码)
  19. centos8 配置 dns_centos 8 集群Linux环境搭建 - 凭栏莫听雨落
  20. 第16课:scratchjr猫与鸟的较量

热门文章

  1. js创建一个电脑对象,该对象要有颜色、重量、品牌、型号,可以看电影、听音乐、打游戏和敲代码。
  2. nodejs入门之数据爬虫
  3. python学习日记(基础数据类型及其方法02)
  4. rpm包的签名问题笔记
  5. python淘宝爬虫登陆功能和下单功能_Python 爬虫实战5 模拟登录淘宝并获取所有订单...
  6. 上班被监控屏幕和摄像头,拒绝就直接开除,员工起诉公司获赔52万元
  7. 2021年起重机械指挥复审模拟考试及起重机械指挥考试试题
  8. MyBatis+PageHelper实现分页
  9. 数据结构-图、二叉树、B(+)树
  10. python中session()是干什么作用的_session是什么意思_session的作用是什么