名称
事件聚合器
目的
当客户端想要订阅事件时,具有大量对象的系统可能会比较复杂。客户端必须单独查找并注册每个对象,如果每个对象都有多个事件,则每个事件都需要单独的订阅。事件聚合器充当许多对象的单一事件源。它注册许多对象的所有事件,允许客户端仅向聚合器注册。
解释
真实世界例子
乔佛里国王坐在铁王座上,统治着维斯特洛的七个王国。他的大部分关键信息来自国王之手,第二指挥。国王之手有许多亲密的顾问,向他提供有关王国发生的事件的相关信息。
通俗的说
事件聚合器是一种事件中介器,它从多个源收集事件并将其传递给已注册的观察者。
编程示例
在我们的编程示例中,我们演示了事件聚合器模式的实现。有些对象是事件侦听器,有些是事件发送器,而事件聚合器两者都是。
java
public interface EventObserver {
void onEvent(Event e);
}
public abstract class EventEmitter {
private final Map<Event, List<EventObserver>> observerLists;
public EventEmitter() {
observerLists = new HashMap<>();
}
public final void registerObserver(EventObserver obs, Event e) {
...
}
protected void notifyObservers(Event e) {
...
}
}KingJoffrey正在侦听来自KingsHand的事件。
java
@Slf4j
public class KingJoffrey implements EventObserver {
@Override
public void onEvent(Event e) {
LOGGER.info("Received event from the King's Hand: {}", e.toString());
}
}KingsHand 正在侦听来自下属 LordBaelish, LordVarys, 和 Scout的事件。 无论他从他们那里听到什么, 他都会交付给 KingJoffrey.
java
public class KingsHand extends EventEmitter implements EventObserver {
public KingsHand() {
}
public KingsHand(EventObserver obs, Event e) {
super(obs, e);
}
@Override
public void onEvent(Event e) {
notifyObservers(e);
}
}例如, LordVarys每个星期天找到一个叛徒并通知 KingsHand.
java
@Slf4j
public class LordVarys extends EventEmitter implements EventObserver {
@Override
public void timePasses(Weekday day) {
if (day == Weekday.SATURDAY) {
notifyObservers(Event.TRAITOR_DETECTED);
}
}
}以下代码段演示了如何构造对象并将其连接在一起。
java
var kingJoffrey = new KingJoffrey();
var kingsHand = new KingsHand();
kingsHand.registerObserver(kingJoffrey, Event.TRAITOR_DETECTED);
kingsHand.registerObserver(kingJoffrey, Event.STARK_SIGHTED);
kingsHand.registerObserver(kingJoffrey, Event.WARSHIPS_APPROACHING);
kingsHand.registerObserver(kingJoffrey, Event.WHITE_WALKERS_SIGHTED);
var varys = new LordVarys();
varys.registerObserver(kingsHand, Event.TRAITOR_DETECTED);
varys.registerObserver(kingsHand, Event.WHITE_WALKERS_SIGHTED);
var scout = new Scout();
scout.registerObserver(kingsHand, Event.WARSHIPS_APPROACHING);
scout.registerObserver(varys, Event.WHITE_WALKERS_SIGHTED);
var baelish = new LordBaelish(kingsHand, Event.STARK_SIGHTED);
var emitters = List.of(
kingsHand,
baelish,
varys,
scout
);
Arrays.stream(Weekday.values())
.<Consumer<? super EventEmitter>>map(day -> emitter -> emitter.timePasses(day))
.forEachOrdered(emitters::forEach);运行示例后的控制台输出。
18:21:52.955 [main] INFO com.iluwatar.event.aggregator.KingJoffrey - Received event from the King's Hand: Warships approaching
18:21:52.960 [main] INFO com.iluwatar.event.aggregator.KingJoffrey - Received event from the King's Hand: White walkers sighted
18:21:52.960 [main] INFO com.iluwatar.event.aggregator.KingJoffrey - Received event from the King's Hand: Stark sighted
18:21:52.960 [main] INFO com.iluwatar.event.aggregator.KingJoffrey - Received event from the King's Hand: Traitor detected类图

适用性
在以下情况下使用事件聚合器模式
- 当您有大量对象作为潜在事件源时,事件聚合器是一个不错的选择。您可以把注册逻辑集中到事件聚合器,而不是让观察者处理所有注册。除了简化注册之外,事件聚合器还简化了使用观察器时的内存管理问题。