设计模式学习笔记(十六)迭代器模式及其在Java 容器中的应用
迭代器(Iterator)模式,也叫做游标(Cursor)模式。我们知道,在Java 容器中,为了提高容器遍历的方便性,我们利用迭代器把遍历逻辑从不同类型的集合类中抽取出来,从而避免向外部暴露集合容器的内部结构。这就是迭代器模式的
一、迭代器模式介绍
迭代器模式也就是提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。它是一种行为型模式,下面就来看看迭代器模式的结构:
1.1 迭代器模式的结构
迭代器模式的结构很简单,就是将聚合对象中的遍历行为分离,并抽象成迭代器类来实现:

Aggregate:抽象聚合接口,定义对聚合对象的一些操作和创建迭代器对象的接口Iterator:抽象迭代器接口,定义访问和遍历聚合元素的接口Aggregate1:具体聚合实现,实现抽象聚合接口,返回一个具体迭代器实例对象Iterator1:具体迭代器实现,实现抽象迭代器接口中所定义的方法
1.2 迭代器模式的实现
根据上面的类图,可以实现如下代码:
/**
* @description: 抽象聚合接口
* @author: wjw
* @date: 2022/4/6
*/
public interface Aggregate {
/**
* 增加对象
* @param obj 对象
*/
void add(Object obj);
/**
* 移除对象
* @param obj 对象
*/
void remove(Object obj);
/**
* 调用迭代器
* @return 迭代器
*/
Iterator getIterator();
}
/**
* @description: 具体迭代器类
* @author: wjw
* @date: 2022/4/6
*/
public class Aggregate1 implements Aggregate{
private List<Object> list = new ArrayList<>();
@Override
public void add(Object obj) {
list.add(obj);
}
@Override
public void remove(Object obj) {
list.remove(obj);
}
@Override
public Iterator getIterator() {
return new Iterator1(list);
}
}
/**
* @description: 抽象迭代器
* @author: wjw
* @date: 2022/4/6
*/
public interface Iterator {
/**
* 调用第一个对象
* @return 对象
*/
Object first();
/**
* 调用下一个对象
* @return 对象
*/
Object next();
/**
* 迭代器中是否还有下一个对象
* @return
*/
boolean hasNext();
}
/**
* @description: 具体迭代器类
* @author: wjw
* @date: 2022/4/6
*/
public class Iterator1 implements Iterator{
private List<Object> list = null;
private int index = -1;
public Iterator1(List<Object> list) {
this.list = list;
}
@Override
public Object first() {
index = 0;
Object obj = list.get(index);
return obj;
}
@Override
public Object next() {
Object obj = null;
if (this.hasNext()) {
obj = list.get(++index);
}
return obj;
}
@Override
public boolean hasNext() {
if (index < list.size() - 1) {
return true;
} else {
return false;
}
}
}
/**
* @description: 客户端类
* @author: wjw
* @date: 2022/4/6
*/
public class Client {
public static void main(String[] args) {
Aggregate1 aggregate1 = new Aggregate1();
aggregate1.add("A");
aggregate1.add("B");
aggregate1.add("C");
System.out.println("聚合对象有:");
Iterator iterator = aggregate1.getIterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println(obj.toString());
}
Object first = iterator.first();
System.out.println("第一个聚合对象是:" + first.toString());
}
}
客户端测试场结果为:
聚合对象有:
A
B
C
第一个聚合对象是:A
二、迭代器模式的应用场景
2.1 Java 集合容器
Java 集合容器中的使用就是容器中的迭代器了,以ArrayList为例,ArrayList是继承Collection的:

我们发现ArrayList类里面实现迭代器接口的内部类:

其中Itr实现Iterator,ListItr继承Itr并实现ListIterator,ListIterator是Iterator功能的扩展。所以实际上ArrayList是抽象聚合和抽象迭代器两者的具体实现,可以画出大致结构图如下:

举个使用ArrayList的例子:
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
Iterator<String> iterator = list.iterator();
System.out.println("ArrayList中的聚合对象为:");
while (iterator.hasNext()) {
String next = iterator.next();
System.out.println(next);
}
}
输出结果:
ArrayList中的聚合对象为:
A
B
C
在日常业务的开发中,迭代器模式使用的场景并不多,下面就来看看关于迭代器的实战
三、迭代器模式实战
在本案例中模拟迭代遍历输出公司中树形结构的组织结构关系中雇员列表:

利用迭代器模式实现的结构如下:

上面结构是以Java容器中迭代器模式基础构建的,左边是迭代器的定义,右边是实现的迭代器功能。具体代码结构图如下:
├─src
│ ├─main
│ │ ├─java
│ │ │ ├─group
│ │ │ │ Employee.java
│ │ │ │ GroupStructure.java
│ │ │ │ Link.java
│ │ │ │
│ │ │ └─lang
│ │ │ Collection.java
│ │ │ Iterable.java
│ │ │ Iterator.java
│ │ │
│ │ └─resources
│ └─test
│ └─java
│ ApiTest.java
对于lang包下是迭代器实现部分,具体代码如下:
/**
* @description: 可迭代接口定义
* @author: wjw
* @date: 2022/4/6
*/
public interface Iterator<E> {
boolean hasNext();
E next();
}
/**
* @description:
* @author: wjw
* @date: 2022/4/6
*/
public interface Iterable<E> {
Iterator<E> iterator();
}
/**
* @description: 集合功能接口
* @author: wjw
* @date: 2022/4/6
*/
public interface Collection<E, L> extends Iterable<E> {
boolean add(E e);
boolean remove(E e);
boolean addLink(String key, L l);
boolean removeLink(String key);
/**
* 继承Iterable接口的方法
* @return Iterator
*/
@Override
Iterator<E> iterator();
}
group包下是组织结构以及聚类对象及其实现,具体代码如下所示:
/**
* @description: 雇员类
* @author: wjw
* @date: 2022/4/6
*/
public class Employee {
private String uId;
private String name;
private String desc;
public Employee(String uId, String name, String desc) {
this.uId = uId;
this.name = name;
this.desc = desc;
}
public String getuId() {
return uId;
}
public void setuId(String uId) {
this.uId = uId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
/**
* @description: 树节点链路
* @author: wjw
* @date: 2022/4/6
*/
public class Link {
private String fromId;
private String toId;
public Link(String fromId, String toId) {
this.fromId = fromId;
this.toId = toId;
}
public String getFromId() {
return fromId;
}
public void setFromId(String fromId) {
this.fromId = fromId;
}
public String getToId() {
return toId;
}
public void setToId(String toId) {
this.toId = toId;
}
}
/**
* @description: 迭代器功能实现
* @author: wjw
* @date: 2022/4/6
*/
public class GroupStructure implements Collection<Employee, Link> {
/**组织ID*/
private String groupId;
/**组织名称*/
private String groupName;
/**雇员列表*/
private Map<String, Employee> employeeMap = new ConcurrentHashMap<>();
/**组织架构关系*/
private Map<String, List<Link>> linkMap = new ConcurrentHashMap<>();
/**反向关系链*/
private Map<String, String> invertedMap = new ConcurrentHashMap<>();
public GroupStructure(String groupId, String groupName) {
this.groupId = groupId;
this.groupName = groupName;
}
@Override
public boolean add(Employee employee) {
return null != employeeMap.put(employee.getuId(), employee);
}
@Override
public boolean remove(Employee employee) {
return null != employeeMap.remove(employee.getuId());
}
@Override
public boolean addLink(String key, Link link) {
invertedMap.put(link.getToId(), link.getFromId());
if (linkMap.containsKey(key)) {
return linkMap.get(key).add(link);
} else {
List<Link> links = new LinkedList<>();
links.add(link);
linkMap.put(key, links);
return true;
}
}
@Override
public boolean removeLink(String key) {
return null != linkMap.remove(key);
}
@Override
public Iterator<Employee> iterator() {
return new Iterator<Employee>() {
HashMap<String, Integer> keyMap = new HashMap<>();
int totalIdx = 0;
//雇员ID,From
private String fromId = groupId;
//雇员ID,To
private String toId = groupId;
@Override
public boolean hasNext() {
return totalIdx < employeeMap.size();
}
@Override
public Employee next() {
List<Link> links = linkMap.get(toId);
int cursorIdx = getCursorIdx(toId);
//同级扫描
if (null == links) {
cursorIdx = getCursorIdx(fromId);
links = linkMap.get(fromId);
}
//上级节点扫描
while (cursorIdx > links.size() - 1) {
fromId = invertedMap.get(fromId);
cursorIdx = getCursorIdx(fromId);
links = linkMap.get(fromId);
}
//获取节点
Link link = links.get(cursorIdx);
toId = link.getToId();
fromId = link.getFromId();
totalIdx++;
//返回最终结果
return employeeMap.get(link.getToId());
}
//给每个层级定义宽度遍历进度
public int getCursorIdx(String key) {
int idx = 0;
if (keyMap.containsKey(key)) {
idx = keyMap.get(key);
keyMap.put(key, ++idx);
} else {
keyMap.put(key, idx);
}
return idx;
}
};
}
}
最后是测试类及其结果:
/**
* @description: 单元测试类
* @author: wjw
* @date: 2022/4/6
*/
public class ApiTest {
private Logger logger = LoggerFactory.getLogger(ApiTest.class);
@Test
public void test_iterator() {
GroupStructure groupStructure = new GroupStructure("1", "ethan");
groupStructure.add(new Employee("2", "花花", "二级部门"));
groupStructure.add(new Employee("3", "豆包", "二级部门"));
groupStructure.add(new Employee("4", "蹦蹦", "三级部门"));
groupStructure.add(new Employee("5", "大烧", "三级部门"));
groupStructure.add(new Employee("6", "虎哥", "四级部门"));
groupStructure.add(new Employee("7", "玲姐", "四级部门"));
groupStructure.add(new Employee("8", "秋雅", "四级部门"));
//添加节点链接
groupStructure.addLink("1", new Link("1", "2"));
groupStructure.addLink("1", new Link("1", "3"));
groupStructure.addLink("2", new Link("2", "4"));
groupStructure.addLink("2", new Link("2", "5"));
groupStructure.addLink("5", new Link("5", "6"));
groupStructure.addLink("5", new Link("5", "7"));
groupStructure.addLink("5", new Link("5", "8"));
Iterator<Employee> iterator = groupStructure.iterator();
while (iterator.hasNext()) {
Employee employee = iterator.next();
logger.info("{},雇员 Id: {} Name: {}", employee.getDesc(), employee.getuId(), employee.getName());
}
}
}
21:50:11.087 [main] INFO ApiTest - 二级部门,雇员 Id: 2 Name: 花花
21:50:11.089 [main] INFO ApiTest - 三级部门,雇员 Id: 4 Name: 蹦蹦
21:50:11.089 [main] INFO ApiTest - 三级部门,雇员 Id: 5 Name: 大烧
21:50:11.089 [main] INFO ApiTest - 四级部门,雇员 Id: 6 Name: 虎哥
21:50:11.089 [main] INFO ApiTest - 四级部门,雇员 Id: 7 Name: 玲姐
21:50:11.089 [main] INFO ApiTest - 四级部门,雇员 Id: 8 Name: 秋雅
21:50:11.089 [main] INFO ApiTest - 二级部门,雇员 Id: 3 Name: 豆包
参考资料
《重学Java设计模式》
http://c.biancheng.net/view/1395.html
设计模式学习笔记(十六)迭代器模式及其在Java 容器中的应用的更多相关文章
- C#设计模式学习笔记:(15)迭代器模式
本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7903617.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第三个模式--迭 ...
- javascript设计模式学习之十六——状态模式
一.状态模式的定义 状态模式的关键是区分事务内部和外部的状态,事务内部状态改变往往会带来事务的行为改变. 状态模式中有意思的一点是,一般我们谈到封装,都是优先封装对象的行为,而非对象的状态.但在状态模 ...
- python3.4学习笔记(十六) windows下面安装easy_install和pip教程
python3.4学习笔记(十六) windows下面安装easy_install和pip教程 easy_install和pip都是用来下载安装Python一个公共资源库PyPI的相关资源包的 首先安 ...
- Java设计模式学习笔记(二) 简单工厂模式
前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 正文开始... 1. 简介 简单工厂模式不属于GoF23中设计模式之一,但在软件开发中应用也较为 ...
- Java设计模式学习笔记(三) 工厂方法模式
前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 简介 上一篇博客介绍了简单工厂模式,简单工厂模式存在一个很严重的问题: 就是当系统需要引入 ...
- Java设计模式学习笔记(四) 抽象工厂模式
前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 抽象工厂模式概述 工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问 ...
- C#设计模式之十六迭代器模式(Iterator Pattern)【行为型】
一.引言 今天我们开始讲"行为型"设计模式的第三个模式,该模式是[迭代器模式],英文名称是:Iterator Pattern.还是老套路,先从名字上来看看."迭代器模 ...
- C#设计模式学习笔记:(23)解释器模式
本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/8242238.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第十一个模式-- ...
- C#设计模式学习笔记:(18)状态模式
本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/8032683.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第六个模式--状 ...
随机推荐
- CF802O题解
太厉害啦,出题人究竟是怎么想到的. 首先这题很显然可以使用费用流:对于 \(i \leq j\),连接一条边 \((i,j+n)\),流量为 \(1\),费用为 \(a_i+b_j\).最后连接 \( ...
- 安装Win7与Ubuntu16.04双系统操作教程
安装主要分为以下几步: 一. 下载Ubuntu 16.04镜像软件: 二. 制作U盘启动盘使用ultraISO: 三. 安装Ubuntu系统: 四. 用EasyBCD 创建启动系统启动引导: (根据个 ...
- First Note
第一篇博客 入驻博客园.
- 什么?Android上面跑Linux?
前言 众所周知,现在程序员因为工作.个人兴趣等对各种系统的需求越来越大,部分人电脑做的还是双系统.其中,比较常见的有各种模拟器.虚拟机在windows上面跑Android.Linux,大家估计都习以为 ...
- 采用WPF开发第二版OFD阅读器,持续完善中,敬请期待!
本人研究OFD多年,采用C#和QT开发了一系列ofd相关软件.在这些产品中,阅读器始终占据着非常重要的位置.可以说,阅读器是直接面向最终客户的产品.是集OFD各类知识之大成的产品.市面上的阅读器产品林 ...
- KestrelServer详解[2]: 网络链接的创建
<注册监听终结点(Endpoint)>已经详细讲述了如何使用KestrelServer,现在我们来简单聊聊这种处理器的总体设计和实现原理.当KestrelServer启动的时候,注册的每个 ...
- 【网鼎杯】jocker--部分代码加壳逆向处理
Main函数,用户输入flag,长度为24位 Wrong函数进行了简单的异或操作 Omg函数进行异或操作,根据提示来看应该是假check Encrypt无法生成伪代码 发现有加壳以及自修改,下断点动调 ...
- 输入URL回车之后,究竟发生了什么
https://blog.csdn.net/androidstarjack/article/details/107031771 在浏览器输入URL回车之后发生了什么?(超详细版) 前言 这个问题已 ...
- Filter是什么?有什么作用?
Filter是过滤器,在请求到达Servlet之前或者响应到达客户端之前截获请求或者响应,对之进行相应的处理.Struts2的控制器就是使用一个Filter实现的.
- 如何使用双重检查锁定在 Java 中创建线程安全的单例?
这个 Java 问题也常被问: 什么是线程安全的单例,你怎么创建它.好吧,在Java 5之前的版本, 使用双重检查锁定创建单例 Singleton 时,如果多个线程试图同时创建 Singleton 实 ...