这是我参与8月更文挑战的第11天,活动详情查看:8月更文挑战java
欢迎来到今天的学习,今天咱们一块儿来学习下编码常常用到可是不会本身去实现的一种模式----迭代器模式。多唠叨几句,我本月将会对java的设计模式精讲,欢迎点击头像,关注个人专栏,我会持续更新,加油!算法
系列文章:设计模式
设计模式之工厂模式markdown
设计模式之访问者模式ide
设计模式之命令者模式post
...持续更新中
话很少说,进入正题
迭代器模式,我想你们对java.util.Iterator 应该不陌生,Iterator在java里面被称之为迭代器。须要说明的是,Java Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法,可用于迭代 ArrayList 和 HashSet 等集合。
因此,看下面官方定义
迭代器模式又叫游标(Cursor)模式,它的原始定义是:迭代器提供一种对容器对象中的各个元素进行访问的方法,而又不须要暴露该对象的内部细节。
今天我会先简单说明下Java Iterator(迭代器),再自行简单实现下迭代器模式。由于在平时开发中,咱们更多的是直接使用它,不多会从零去实现一个迭代器。
可是今天咱们主要讲的是迭代器模式,宗旨仍是要弄懂原理,更好的运用此模式。
Iterator接口也是Java集合框架的成员,与Collection和Map两个系列的集合不同的是Collection和Map系列主要用于充当容器的做用,而Iterator正如其名字同样是主要用于迭代访问Collection集合中的元素,Iterator对象也被称为迭代器
该接口定义了四种方法:
能够看到Java迭代器就是来为各类容器提供了公共的操做接口。这样使得对容器的遍历操做与其具体的底层实现相隔离,达到解耦的效果。迭代器模式就是这种思想,下面咱们用自行实现一个简单的迭代器。
先看张图(此图来源于网络):
从上图中,咱们能够看到四种关键角色:
抽象集合类(Aggregate):建立和抽象迭代器类相关联的方法,同时能够添加其余集合类须要的方法。
具体集合类(ConcreteAggregate):实现抽象集合类声明的全部方法,在具体使用集合类时会建立对应具体的迭代器类
抽象迭代器类(Iterator):定义统一的迭代器方法 hasNext() 和 next(),用于判断当前集合中是否还有对象以及按顺序读取集合中的当前对象。
具体迭代器类(ConcreteIterator):实现了抽象迭代器类声明的方法,处理具体集合中对对象位置的偏移以及具体对象数据的传输。
咱们根据这套模式结合java Iterator 来自行实现 代码以下:
//第一步 咱们也先建立一个接口迭代器 泛型
//建立抽象迭代器 IteratorIterator
public interface IteratorIterator<E> {
void reset(); //重置为第一个元素
E next(); //获取下一个元素
E currentItem(); //检索当前元素
boolean hasNext(); //判断是否还有下一个元素存在.
}
//接下来,咱们再来定义抽象集合 ListList(一样为了和 Java 中的 List 接口区别开),
//也声明为泛型接口,接收类型参数 E,声明一个建立迭代器 IteratorIterator 的方法 iterator()。
public interface ListList<E> {
IteratorIterator<E> iterator();
}
//而后,咱们构造一个对象 Message,对象中只包含 消息体body 属性以及其构造函数和 get、set 方法。
public class Message {
private String body;
public Topic(String body) {
super();
this.body = body;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
}
复制代码
再接着实现一个具体的迭代器类 MessageIterator,其中包含属性为 Message 的数组和一个记录对象存储位置的对象 position。当咱们执行 next() 方法时,会获取当前记录位置的对象,至于 reset() 则会重置对象在数组中的位置为 0,currentItem() 方法则会返回当前位置下的对象,hasNext() 则判断当前位置是否越界。
public class MessageIterator implements IteratorIterator<Message> {
private Message[] messages;
private int position;
public MessageIterator(Message[] messages) {
this.messages = messages;
position = 0;
}
@Override
public void reset() {
position = 0;
}
@Override
public Message next() {
return messages[position++];
}
@Override
public Message currentItem() {
return messages[position];
}
@Override
public boolean hasNext() {
if(position >= messages.length) {
return false;
}
return true;
}
}
复制代码
一样,还须要实现一个具体的集合类 MessageList,该类中只实现一个建立迭代器的方法,返回对应具体迭代器的类方法。
public class MessageList implements ListList<Message>{
private Message[] messages;
public MessageList(Message[] messages) {
this.messages = messages;
}
@Override
public IteratorIterator<Message> iterator() {
return new MessageIterator(topics);
}
}
复制代码
//单元测试下
public class Client {
public static void main(String[] args) {
//定义消息体,装3条消息
Message[] messages = new Message[5];
messages[0] = new Topic("topic1");
messages[1] = new Topic("topic2");
messages[2] = new Topic("topic3");
ListList<Message> list = new MessageList(messages);
//迭代器循环
IteratorIterator<Message> iterator = list.iterator();
while(iterator.hasNext()) {
Message currentTopic = iterator.next();
System.out.println(currentTopic.getBody());
}
}
}
//输出结果
topic1
topic2
topic3
复制代码
OK,代码到这里就结束了,咱们能够看到原理仍是比较简单的。就是经过为集合对象建立统一的迭代器 Iterator 来统一对集合里的对象进行访问
为何使用迭代器模式?
第一个,减小程序中重复的遍历代码。
第二个,为了隐藏统一遍历集合的方法逻辑。迭代器模式把对不一样集合类的访问逻辑抽象出来,这样在不用暴露集合内部结构的状况下,能够隐藏不一样集合遍历须要使用的算法,同时还可以对外提供更为简便的访问算法接口。
优势:
一、能够减小直接使用 for 循环的重复代码问题
二、知足开闭原则。当须要对新的对象集合进行扩展时,只须要新增具体的对象迭代器和具体的集合类便能方便地进行扩展。
缺点:
A、 增长子类数量。当新增某种集合类型的迭代器时,还得新增对应类型的迭代器和集合对象,这会增长不少不一样的子类
感谢你的阅读,若是你感受学到了东西,麻烦您点赞,关注。
我已经将本章收录在专题里,点击下方专题,关注专栏,我会天天发表干货,本月我会持续输入设计模式。
加油! 咱们下期再见!