迭代器(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实现IteratorListItr继承Itr并实现ListIteratorListIteratorIterator功能的扩展。所以实际上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 容器中的应用的更多相关文章

  1. C#设计模式学习笔记:(15)迭代器模式

    本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7903617.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第三个模式--迭 ...

  2. javascript设计模式学习之十六——状态模式

    一.状态模式的定义 状态模式的关键是区分事务内部和外部的状态,事务内部状态改变往往会带来事务的行为改变. 状态模式中有意思的一点是,一般我们谈到封装,都是优先封装对象的行为,而非对象的状态.但在状态模 ...

  3. python3.4学习笔记(十六) windows下面安装easy_install和pip教程

    python3.4学习笔记(十六) windows下面安装easy_install和pip教程 easy_install和pip都是用来下载安装Python一个公共资源库PyPI的相关资源包的 首先安 ...

  4. Java设计模式学习笔记(二) 简单工厂模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 正文开始... 1. 简介 简单工厂模式不属于GoF23中设计模式之一,但在软件开发中应用也较为 ...

  5. Java设计模式学习笔记(三) 工厂方法模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 简介 上一篇博客介绍了简单工厂模式,简单工厂模式存在一个很严重的问题: 就是当系统需要引入 ...

  6. Java设计模式学习笔记(四) 抽象工厂模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 抽象工厂模式概述 工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问 ...

  7. C#设计模式之十六迭代器模式(Iterator Pattern)【行为型】

    一.引言   今天我们开始讲"行为型"设计模式的第三个模式,该模式是[迭代器模式],英文名称是:Iterator Pattern.还是老套路,先从名字上来看看."迭代器模 ...

  8. C#设计模式学习笔记:(23)解释器模式

    本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/8242238.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第十一个模式-- ...

  9. C#设计模式学习笔记:(18)状态模式

    本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/8032683.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第六个模式--状 ...

随机推荐

  1. NETPLIER : 一款基于概率的网络协议逆向工具(一)理论

    本文系原创,转载请说明出处:信安科研人 关注微信公众号 信安科研人 获取更多网络安全学术技术资讯 今日介绍一篇发表在2021 NDSS会议上的一项有关协议逆向的工作: @ 目录 1 网络协议逆向工程简 ...

  2. k8s 开船记-脚踏两只船:船儿还是旧的好,不翻船才是硬道理

    自从上次开始脚踏两只船(2个独立的k8s集群同时运行),园子暂时用奢侈的土豪方式过上了安稳的船上生活. 这种方式除了费钱之外,还带来一个问题,我们的集装箱自动装船系统(基于gitlab-ci的自动化部 ...

  3. SpringCloud-Consul

    1. Consul 简介 Consul是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发现与配置.与其它分布式服 务注册与发现的方案,Consul 的方案更"一站式&qu ...

  4. 《前端运维》二、Nginx--1基本概念及安装

    一.Nginx基本概念 简单来说,Nginx就是一个代理服务器,什么是代理服务器呢?也就是当我们访问服务器的时候,请求不会直接请求到服务器,中间会有个代理,代理会预先于服务器处理这些请求,最后由代理决 ...

  5. Linux详解 --- 进程管理

    镜像下载.域名解析.时间同步请点击 阿里云开源镜像站 进程管理一览 接下来的几篇博客,我将主要按照这个思维导图的划分去进行讲解. 管理 在理解什么是进程管理之前,我想我们可以先理解一下什么是管理! 问 ...

  6. Fiddler修改接口下行数据,mock测试

    应用场景:在不修改服务器代码的情况下,临时改变接口下行数据值,便于查看界面效果.. 使用工具:Fiddler 使用方法:连接Fiddler,使用代理. Fiddler配置方法如下: 1.定位到Fidd ...

  7. C# WinForm 解决子窗体放大后,子窗体图标放大的问题

    解决子窗体放大后,子窗体的图标占用主窗体的菜单栏的问题. C#子窗体最大化时, 那个图标跑到主窗体的前面去了, 造成界面不统一也不美观. 所以需要进行处理, 只要有主窗体的菜单ItemAdded事件中 ...

  8. CF1225E Rock Is Push (计数)

    观察性质计数题orz小贺 考场上跟榜才切 我们只能往下和往右走,那么只有连续的往下和往右可能会造成不合法的情况!如果当前这一步是向右,那么只有它前面连续的一段向右可能影响到它. 考虑把连续的向右/下一 ...

  9. 100行代码实现HarmonyOS“画图”应用,eTS开发走起!

    本期我们给大家带来的是"画图"应用开发者Rick的分享,希望能给你的HarmonyOS开发之旅带来启发~ 介绍 2021年的华为开发者大会(HDC2021)上,HarmonyOS ...

  10. SpringBoot:自定义注解实现后台接收Json参数

    0.需求 在实际的开发过程中,服务间调用一般使用Json传参的模式,SpringBoot项目无法使用@RequestParam接收Json传参 只有@RequestBody支持Json,但是每次为了一 ...