迭代器模式
迭代器模式,常见的就是我们日常使用的 iterator
遍历。虽然这个设计模式在我们的实际业务开发中的场景并不多,但却几乎每天都要使用 jdk 为我们提供的 list
集合遍历。另外增强的 for 循环虽然是循环输出数据,但是他不是迭代器模式。迭代器模式的特点是实现 Iterable
接口,通过 next 的方式获取集合元素,同时具备对元素的删除等操作。而增强的 for 循环是不可以的。
这种设计模式的优点是可以让我们以相同的方式,遍历不同的数据结构元素,这些数据结构包括;数组、链表、树等,而用户在使用遍历的时候并不需要去关心每一种数据结构的遍历处理逻辑,从让使用变得统一易用。
优点:
缺点:由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。
使用场景:
本次模拟迭代遍历输出公司中树形结构的组织架构关系中雇员列表。
大部分公司的组织架构都是金字塔结构,也就这种树形结构,分为一级、二级、三级等部门,每个组织部门由雇员填充,最终体现出一个整体的树形组织架构关系。
一般我们常用的遍历就是 jdk 默认提供的方法,对 list 集合遍历。但是对于这样的偏业务特性较大的树形结构,如果需要使用到遍历,那么就可以自己来实现。接下来我们会把这个组织层次关系通过树形数据结构来实现,并完成迭代器功能。
在实现迭代器模式之前可以先阅读下 java 中 list 方法关于 iterator 的实现部分,几乎所有的迭代器开发都会按照这个模式来实现,这个模式主要分为以下几块;
代码结构:
雇员实体类
@Data
public class Employee {
// ID
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;
}
}
树节点链路
@Data
public class Link {
// 雇员ID
private String fromId;
// 雇员ID
private String toId;
public Link(String fromId, String toId) {
this.fromId = fromId;
this.toId = toId;
}
}
迭代器定义
public interface Iterator<E> {
boolean hasNext();
E next();
}
可迭代接口定义
public interface Iterable<E> {
Iterator<E> iterator();
}
集合功能接口定义
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);
Iterator<E> iterator();
}
(核心)迭代器功能实现
public class GroupStructure implements Collection<Employee, Link> {
// 组织ID,也是一个组织链的头部ID
private String groupId;
// 组织名称
private String groupName;
// 雇员列表
private Map<String, Employee> employeeMap = new ConcurrentHashMap<String, Employee>();
// 组织架构关系;id->list
private Map<String, List<Link>> linkMap = new ConcurrentHashMap<String, List<Link>>();
// 反向关系链
private Map<String, String> invertedMap = new ConcurrentHashMap<String, String>();
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 o) {
return null != employeeMap.remove(o.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<Link>();
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<String, Integer>();
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;
}
};
}
}
迭代器实现思路
测试类:
@Slf4j
public class ApiTest {
@Test
public void test_iterator() {
// 数据填充
GroupStructure groupStructure = new GroupStructure("1", "lixj");
// 雇员信息
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", "秋雅", "四级部门"));
// 节点关系 1->(1,2) 2->(4,5)
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();
log.info("{},雇员 Id:{} Name:{}", employee.getDesc(), employee.getUId(), employee.getName());
}
}
}
测试结果:
14:40:05.876 [main] INFO ApiTest - 二级部门,雇员 Id:2 Name:花花
14:40:05.879 [main] INFO ApiTest - 三级部门,雇员 Id:4 Name:蹦蹦
14:40:05.879 [main] INFO ApiTest - 三级部门,雇员 Id:5 Name:大烧
14:40:05.879 [main] INFO ApiTest - 四级部门,雇员 Id:6 Name:虎哥
14:40:05.879 [main] INFO ApiTest - 四级部门,雇员 Id:7 Name:玲姐
14:40:05.879 [main] INFO ApiTest - 四级部门,雇员 Id:8 Name:秋雅
14:40:05.879 [main] INFO ApiTest - 二级部门,雇员 Id:3 Name:豆包
Process finished with exit code 0
Copyright: 采用 知识共享署名4.0 国际许可协议进行许可 Links: https://lixj.fun/archives/设计模式-迭代器模式