行为型模式:迭代器模式
LieBrother原文: 行为型模式:迭代器模式
十一大行为型模式之六:迭代器模式。
简介
姓名 :迭代器模式
英文名 :Iterator Pattern
价值观 :人生没有回头路
个人介绍 :
Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation. 它提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。 (来自《设计模式之禅》)
你要的故事
大家伙听歌频率高么?是不是经常听歌曲来放松心情?我是经常会听歌,心情不好的时候听歌,心情好的时候也听歌。。。今天讲的迭代器模式,我们就拿听歌这件事来说说,大家都知道听歌有几种模式:单曲循环、列表循环、随机等等。。。现在网易云音乐还多了一个心动模式。
既然说到迭代器模式,那这里就要着重讲讲列表循环这个听歌模式,其他的就先抛到脑后。在列表循环中,歌曲从第一条播放到最后一条,也就是一个遍历歌单的过程。我们有 2 种实现方式,一种是没有迭代器,通过获取歌单,用 for 循环遍历每一个歌曲,然后播放;另外一种是使用迭代器,获取歌单的一个迭代器,通过迭代器来遍历每一个歌曲,然后播放。下面我们就用代码来实现这 2 种方式。
木有迭代器
public class NoIteratorTest { public static void main(String[] args) { NetEaseMusic1 netEaseMusic1 = new NetEaseMusic1(); netEaseMusic1.listenToMusicByLoop(); } } /** * 网易云音乐 */ class NetEaseMusic1 { private IList1 songList; public NetEaseMusic1() { songList = new SongList1(3); songList.add(new Song("让我留在你身边", "陈奕迅")); songList.add(new Song("你曾是少年", "SHE")); songList.add(new Song("Perfect", "Ed Sheeran")); } /** * 列表循环 */ public void listenToMusicByLoop() { for (int i = 0; i < songList.size(); i++) { System.out.println("听歌:" + ((ISong)songList.get(i)).getSongInfo()); } } } /** * 容器接口 */ interface IList1 { void add(Object object); Object get(int index); int size(); } /** * 歌单 */ class SongList1 implements IList1 { private ISong[] songs; private int index; private int size; public SongList1(int size) { songs = new ISong[size]; index = 0; size = 0; } @Override public void add(Object object) { songs[index++] = (ISong) object; size ++; } @Override public Object get(int index) { if (index < size) { return songs[index]; } return null; } @Override public int size() { return size; } } /** * 歌曲接口 */ interface ISong { String getSongInfo(); } /** * 歌曲 */ class Song implements ISong{ private String name; private String singer; public Song(String name, String singer) { this.name = name; this.singer = singer; } @Override public String getSongInfo() { return this.name + "--" + this.singer; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSinger() { return singer; } public void setSinger(String singer) { this.singer = singer; } } 打印结果: 听歌:让我留在你身边--陈奕迅 听歌:你曾是少年--SHE 听歌:Perfect--Ed Sheeran
我们定义了 ISong 接口,里面有个 getSongInfo() 方法来获取歌曲信息,用 Song 类来定义歌曲。没有用 Java 自带的容器来存放歌曲,这里实现了一个自定义容器接口 IList1,定义 SongList1 来做歌曲的容器,为什么不用 Java 自带的 ArrayList 等等?因为 Java 自带的已经实现了迭代器功能了,我们这里自定义其实就是在模仿自带的容器的实现。NetEaseMusic1 类是充当网易云音乐客户端,在 listenToMusicByLoop() 方法中,我们可以看到是获取了歌单 songList,然后一个一个遍历,这是没有使用迭代器的代码。
下面看一下使用迭代器的代码是怎么样的。
用迭代器实现遍历
public class IteratorTest { public static void main(String[] args) { NetEaseMusic2 netEaseMusic2 = new NetEaseMusic2(); netEaseMusic2.listenToMusicByLoop(); } } /** * 网易云音乐 */ class NetEaseMusic2{ private IList2 songList; public NetEaseMusic2() { songList = new SongList2(3); songList.add(new Song("让我留在你身边", "陈奕迅")); songList.add(new Song("你曾是少年", "SHE")); songList.add(new Song("Perfect", "Ed Sheeran")); } /** * 列表循环 */ public void listenToMusicByLoop() { IIterator iterator = songList.iterator(); while (iterator.hasNext()) { System.out.println("听歌:" + ((ISong)iterator.next()).getSongInfo()); } } } /** * 容器接口 */ interface IList2 { IIterator iterator(); void add(Object object); Object get(int index); int size(); } /** * 歌单 */ class SongList2 implements IList2 { private ISong[] songs; private int index; private int size; public SongList2(int size) { songs = new ISong[size]; index = 0; size = 0; } @Override public IIterator iterator() { return new IteratorImpl(this); } @Override public void add(Object object) { songs[index++] = (ISong) object; size ++; } @Override public Object get(int index) { if (index < size) { return songs[index]; } return null; } @Override public int size() { return size; } } /** * 迭代器 */ interface IIterator { Object next(); boolean hasNext(); } /** * 迭代器实现类 */ class IteratorImpl implements IIterator { private IList2 list; private int index; public IteratorImpl(IList2 list) { this.list = list; this.index = 0; } @Override public Object next() { return list.get(index++); } @Override public boolean hasNext() { if (index < list.size()) { return true; } return false; } } 打印结果: 听歌:让我留在你身边--陈奕迅 听歌:你曾是少年--SHE 听歌:Perfect--Ed Sheeran
代码中我们自定义了一个迭代器接口 IIterator 和迭代器具体实现类 IteratorImpl,有关键的 2 个方法,hasNext() 判断是否有存在下一个元素,next() 获取下一个元素。而 IList2 接口则比 IList1 接口多了一个获取迭代器的方法 iterator(),这让网易云音乐在遍历歌单的时候,不用直接使用 songList 来遍历,而可以通过 songList.iterator() 获取迭代器来实现遍历的过程。NetEaseMusic2.listenToMusicByLoop() 这个方法里面就直接获取迭代器来遍历了。
代码: Iterator Pattern
总结
迭代器模式是所有设计模式中使用最广泛的,有不少开发同学知道迭代器,但是不知道它是设计模式的。虽然迭代器的代码会比没有迭代器的代码复杂,但是加上迭代器可以让容器有统一的遍历代码风格,不用各自去实现遍历方法,有更好的封装性。在 Java 中,迭代器已经运用很广泛,比如 Java 中访问 MySQL 获取数据就是用迭代器来遍历数据的。好了,迭代器模式就讲到这,大家知道的知识就不多说啦。
参考资料:《大话设计模式》、《设计模式之禅》
推荐阅读:
希望文章对您有所帮助,设计模式系列会持续更新,感兴趣的同学可以关注公众号:LieBrother,第一时间获取文章推送阅读,也可以一起交流,交个朋友。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
记一次神奇的Mysql死锁排查
背景 说起Mysql死锁,之前写过一次有关Mysql加锁的基本介绍,对于一些基本的Mysql锁或者死锁都有一个简单的认识,可以看下这篇文章为什么开发人员需要了解数据库锁。有了上面的经验之后,本以为对于死锁都能手到擒来,没想到再一个阳光明媚的下午报出了一个死锁,但是这一次却没想象的那么简单。 问题初现 在某天下午,突然系统报警,抛出个异常: 仔细一看好像是事务回滚异常,写着的是因为死锁回滚,原来是个死锁问题,由于我对Mysql锁还是有一定 了解的,于是开始主动排查这个问题。 首先在数据库中查找Innodb Status,在Innodb Status中会记录上一次死锁的信息,输入下面命令: SHOW ENGINE INNODB STATUS 死锁信息如下,sql信息进行了简单处理: ------------------------ LATEST DETECTED DEADLOCK ------------------------ 2019-02-22 15:10:56 0x7eec2f468700 *** (1) TRANSACTION: TRANSACTION 2660206487, A...
- 下一篇
Nginx多进程高并发、低时延、高可靠机制在缓存(redis、memcache)twemproxy代理中的应用
0. 手把手教你做中间件、高性能服务器、分布式存储技术交流群 手把手教你做中间件、高性能服务器、分布式存储等(redis、memcache、nginx、大容量redis pika、rocksdb、mongodb、wiredtiger存储引擎、高性能代理中间件),git地址如下: git地址:https://github.com/y123456yz/middleware_development_learning 1. 开发背景 现有开源缓存代理中间件有twemproxy、codis等,其中twemproxy为单进程单线程模型,只支持memcache单机版和redis单机版,都不支持集群版功能。 由于twemproxy无法利用多核特性,因此性能低下,短连接QPS大约为3W,长连接QPS大约为13W,同时某些场景时延抖动厉害。 为了适应公有云平台上业务方的高并发需求,因此决定借助于twemproxy来做二次开发,把nginx的高性能、高可靠、高并发机制引入到twemproxy中,通过master+多worker进程来实现七层转发功能。 2 Twemproxy 2.1Twempr...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Red5直播服务器,属于Java语言的直播服务器
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- CentOS7设置SWAP分区,小内存服务器的救世主
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS8安装Docker,最新的服务器搭配容器使用
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- Hadoop3单机部署,实现最简伪集群
- Mario游戏-低调大师作品
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程