1. 迭代器模式深度解析
1.1 为什么需要迭代器模式
在软件开发中,我们经常需要处理各种集合对象(如数组、链表、树等)。直接暴露集合的内部结构会导致几个严重问题:
- 客户端代码与具体集合实现强耦合,一旦集合结构变化就需要修改所有遍历代码
- 同一集合可能存在多种遍历方式(如正序、逆序、按条件过滤等)
- 集合内部数据的存储方式可能非常复杂(如数据库结果集、文件系统目录树)
迭代器模式通过将遍历行为抽象为独立的迭代器对象,完美解决了这些问题。就像现实生活中的博物馆导览器,无论展品如何布置,游客只需按照导览器的指引就能有序参观。
1.2 迭代器模式的核心结构
标准的迭代器模式包含以下关键角色:
-
Iterator(抽象迭代器)
- 定义访问和遍历元素的接口
- 通常包含hasNext()和next()等基本操作
- 示例代码:
java复制public interface Iterator<T> { boolean hasNext(); T next(); void remove(); // 可选 }
-
ConcreteIterator(具体迭代器)
- 实现迭代器接口
- 记录遍历的当前位置
- 示例(数组迭代器):
java复制public class ArrayIterator<T> implements Iterator<T> { private T[] array; private int position = 0; public ArrayIterator(T[] array) { this.array = array; } @Override public boolean hasNext() { return position < array.length; } @Override public T next() { return array[position++]; } }
-
Aggregate(抽象聚合类)
- 定义创建迭代器对象的接口
- 示例:
java复制public interface Aggregate<T> { Iterator<T> createIterator(); }
-
ConcreteAggregate(具体聚合类)
- 实现创建具体迭代器的工厂方法
- 示例:
java复制public class ConcreteAggregate<T> implements Aggregate<T> { private T[] items; public ConcreteAggregate(T[] items) { this.items = items; } @Override public Iterator<T> createIterator() { return new ArrayIterator<>(items); } }
1.3 迭代器模式的典型应用场景
-
跨集合的统一遍历接口
- 无论底层是数组、链表还是树结构,客户端都可以用相同的迭代器接口遍历
- 示例:
java复制void processCollection(Aggregate<String> collection) { Iterator<String> it = collection.createIterator(); while(it.hasNext()) { String item = it.next(); System.out.println(item); } }
-
支持多种遍历方式
- 可以为同一集合提供不同迭代器(如正序、逆序、过滤等)
- 示例(逆序迭代器):
java复制public class ReverseArrayIterator<T> implements Iterator<T> { private T[] array; private int position; public ReverseArrayIterator(T[] array) { this.array = array; position = array.length - 1; } @Override public boolean hasNext() { return position >= 0; } @Override public T next() { return array[position--]; } }
-
延迟加载与流式处理
- 迭代器可以按需加载数据,特别适合大数据集
- 示例(数据库结果集迭代器):
java复制public class DbResultIterator implements Iterator<Record> { private ResultSet rs; private boolean hasNext; public DbResultIterator(ResultSet rs) { this.rs = rs; try { hasNext = rs.next(); } catch(SQLException e) { hasNext = false; } } @Override public boolean hasNext() { return hasNext; } @Override public Record next() { Record record = new Record(rs); try { hasNext = rs.next(); } catch(SQLException e) { hasNext = false; } return record; } }
提示:在实现迭代器时,特别要注意并发修改问题。当集合在迭代过程中被修改时,应该抛出ConcurrentModificationException。这是Java集合框架中的常见做法。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 迭代器模式的进阶应用与实现细节
2.1 内部迭代器 vs 外部迭代器
迭代器可以分为两种基本类型:
-
外部迭代器(主动迭代)
- 客户端控制迭代过程
- 优点:灵活,可以控制迭代节奏
- 缺点:客户端代码稍复杂
- 示例:
java复制Iterator<String> it = list.iterator(); while(it.hasNext()) { String item = it.next(); // 处理item }
-
内部迭代器(被动迭代)
- 迭代器控制迭代过程,客户端提供回调
- 优点:客户端代码简洁
- 缺点:灵活性较低
- 示例(Java 8 Stream API):
java复制list.forEach(item -> { // 处理item });
2.2 迭代器模式在各语言中的实现
不同语言对迭代器模式的支持程度不同:
| 语言 | 原生支持 | 典型实现方式 |
|---|---|---|
| Java | 是 (java.util.Iterator) | 接口+实现类 |
| C++ | 是 (STL迭代器) | 运算符重载 |
| Python | 是 (__iter__协议) | 生成器函数 |
| JavaScript | 是 (Symbol.iterator) | 生成器函数 |
以Python为例,迭代器协议非常简单:
python复制class MyIterator:
def __iter__(self):
return self
def __next__(self):
# 返回下一个元素或raise StopIteration
pass
2.3 迭代器模式的性能考量
实现迭代器时需要考虑以下性能因素:
-
内存占用
- 每次迭代是否创建新对象
- 是否缓存了全部数据
-
计算复杂度
- next()操作的时间复杂度
- hasNext()操作的时间复杂度
-
并发性能
- 是否支持多线程并发迭代
- 迭代过程中的集合修改策略
以Java的ArrayList迭代器为例,它直接访问底层数组,非常高效:
java复制private class Itr implements Iterator<E> {
int cursor; // 下一个元素的索引
int lastRet = -1; // 上一个返回的元素的索引
public boolean hasNext() {
return cursor != size;
}
public E next() {
checkForComodification();
int i = cursor;
E next = get(i);
lastRet = i;
cursor = i + 1;
return next;
}
}
3. 中介者模式深度解析
3.1 中介者模式要解决的问题
在复杂的系统中,对象之间往往存在大量的直接交互,导致:
- 系统结构混乱,对象间耦合度高
- 修改一个对象可能影响多个其他对象
- 难以单独理解或复用单个组件
中介者模式通过引入一个中介对象来封装对象间的交互,就像机场的塔台控制所有飞机的起降一样,使对象间的通信变得有序和可控。
3.2 中介者模式的核心结构
中介者模式包含以下关键角色:
-
Mediator(抽象中介者)
- 定义同事对象到中介者的接口
- 示例:
java复制public interface Mediator { void notify(Colleague sender, String event); }
-
ConcreteMediator(具体中介者)
- 实现协调各同事对象的逻辑
- 了解并维护各个同事对象
- 示例:
java复制public class ConcreteMediator implements Mediator { private ComponentA componentA; private ComponentB componentB; @Override public void notify(Colleague sender, String event) { if(sender == componentA && event.equals("click")) { componentB.doSomething(); } // 其他交互逻辑... } }
-
Colleague(抽象同事类)
- 定义同事对象的接口
- 持有中介者的引用
- 示例:
java复制public abstract class Colleague { protected Mediator mediator; public Colleague(Mediator mediator) { this.mediator = mediator; } }
-
ConcreteColleague(具体同事类)
- 实现具体业务逻辑
- 通过中介者与其他同事通信
- 示例:
java复制public class ComponentA extends Colleague { public ComponentA(Mediator mediator) { super(mediator); } public void click() { mediator.notify(this, "click"); } }
3.3 中介者模式的典型应用场景
-
GUI系统中的组件交互
- 按钮、文本框等组件通过对话框中介者通信
- 示例:登录对话框协调用户名输入框和密码输入框
-
聊天室系统
- 用户不直接相互发送消息,而是通过聊天室中介者
- 示例:
java复制public class ChatRoom implements Mediator { private List<User> users = new ArrayList<>(); @Override public void notify(Colleague sender, String message) { for(User user : users) { if(user != sender) { user.receive(message); } } } }
-
航空管制系统
- 飞机不直接相互通信,而是通过塔台中介者
- 塔台协调飞机的起飞、降落和航线
注意:中介者模式虽然能减少对象间的耦合,但如果中介者本身变得过于复杂,就可能成为系统的瓶颈和单点故障。设计时需要平衡中介者的职责范围。
4. 中介者模式的实现变体与最佳实践
4.1 事件总线:中介者模式的现代实现
现代框架中常用事件总线来实现中介者模式:
-
基本概念
- 组件发布事件到总线
- 其他组件订阅感兴趣的事件
- 总线负责事件路由
-
示例实现
java复制public class EventBus { private Map<Class<?>, List<Consumer<?>>> handlers = new HashMap<>(); public <T> void subscribe(Class<T> eventType, Consumer<T> handler) { handlers.computeIfAbsent(eventType, k -> new ArrayList<>()).add(handler); } public <T> void publish(T event) { List<Consumer<?>> consumers = handlers.get(event.getClass()); if(consumers != null) { consumers.forEach(c -> ((Consumer<T>)c).accept(event)); } } } -
使用示例
java复制// 订阅 eventBus.subscribe(LoginEvent.class, event -> { System.out.println("User logged in: " + event.getUsername()); }); // 发布 eventBus.publish(new LoginEvent("alice"));
4.2 中介者模式与观察者模式的比较
两种模式都用于对象间通信,但有重要区别:
| 特性 | 中介者模式 | 观察者模式 |
|---|---|---|
| 通信方向 | 双向(通过中介者) | 单向(主题→观察者) |
| 耦合度 | 同事对象间解耦 | 观察者知道主题 |
| 复杂度 | 中介者可能变得复杂 | 相对简单 |
| 适用场景 | 多对多复杂交互 | 一对多依赖关系 |
4.3 中介者模式的性能优化
-
异步中介者
- 使用消息队列实现非阻塞通信
- 示例:
java复制public class AsyncMediator implements Mediator { private Executor executor = Executors.newCachedThreadPool(); @Override public void notify(Colleague sender, String event) { executor.execute(() -> { // 异步处理事件 }); } }
-
中介者链
- 将复杂中介者拆分为多个专门的中介者
- 每个中介者处理特定类型的交互
-
缓存常用协调结果
- 对于重复的协调请求,可以缓存结果
- 示例:
java复制public class CachingMediator implements Mediator { private Map<String, Object> cache = new HashMap<>(); @Override public void notify(Colleague sender, String event) { String key = sender.getClass() + ":" + event; if(!cache.containsKey(key)) { // 计算并缓存结果 } // 使用缓存结果 } }
在实际项目中,我经常发现开发者会过度使用中介者模式,导致中介者类变得臃肿。一个好的经验法则是:当中介者方法超过500行代码,就应该考虑拆分或重构了。另外,使用中介者模式时,要特别注意线程安全问题,特别是在Web或移动应用等高并发环境中。
