我使用的是Spring。我实现了互联网上例子中所示的模式Observer。
@Component
public class ObserverManager {
private Map<String, List<IObserver>> observers = new HashMap<>();
public void subscribe(String type, IObserver observer){
// do something
}
public void notifyObserver(String type, Object data){
observers.get(type).forEach(observer -> observer.update(data));
}
// more
}
@Component
public class NewsObserver implements IObserver {
@Override
public void update(Object o) {
//do something
}
}
但我不明白如何正确地将观察者添加到ObserverManager中。它可以通过构造函数注入。但是如果观察者是7-8个?这对构造函数来说是一个很大的问题.如何正确解决这个问题呢?
解决这个问题的方法有很多,其中包括(可以有更多)。
观察员自己登记
解决这个问题的一个很常见的方法是让观察者自己注册,这是很干净的,因为观察者很清楚自己要观察什么。
@Component
public class NewsObserver implements IObserver {
@Autowired
public NewsObserver(IObserverManager observerManager) {
observerManager.subscribe("interestingType", this);
}
@Override
public void update(Object o) {
//do something
}
}
注入一个集合
另一种方法是使用 List<IObserver>
在 ObserverManager
构造函数。
@Autowired
public ObserverManager(List<IObserver> observers) {
observersByType.put(type, observers);
}
但是这个类型是从哪里来的?如果是观察者知道的,你就必须先迭代接收到的列表,从观察者那里得到合适的类型,然后用这个类型注册每一个人。
使用配置Bean
通过放弃 @Component
来自 NewsObserver
并手动注册豆豆,你可以做这样的事情。
@Bean
@Autowired
public IObserver newsObserver1(ObserverManager manager) {
IObserver o1 = new NewsObserver();
manager.subscribe("type1", o1);
return o1;
}
@Bean
@Autowired
public IObserver newsObserver2(ObserverManager manager) {
IObserver o2 = new NewsObserver();
manager.subscribe("type2", o2);
return o2;
}
选择什么?
我想这要看情况。
IMO,更干净的方法是第一种。请注意,注入一个模拟的 ObserverManager
进行测试。还有谁比观察者自己更清楚观察者对什么类型的新闻感兴趣呢?观察者可以控制自己观察的内容和时间,以及何时停止观察。
EDIT: 正如评论中正确指出的那样,这引入了观察者和观察者管理者之间的循环依赖关系。就目前而言,因为观察者管理器的实例并没有保存在观察者中,而且你不可能为同一个观察者实例调用观察者构造函数两次,所以循环不会发生。但这还是一个设计上的味道,将来可能会导致问题。
两个实体之间的循环依赖一般是通过引入一个第三方来管理这两个实体之间的关系来解决的,这就导致了我们提到的一个替代方案。
配置豆的方法很有意思,在这个意义上,没有依赖性的 NewsObserver
因此,没有循环的依赖性,它只是坐在那里等待更新。但需要注意的是,管理哪个观察者接收哪种类型以及何时停止订阅需要在观察者之外完成,这可能看起来并不自然。
注意事项
作为一个补充,可以考虑使用Multimap(例如,可以使用 番石榴)的观察员地图。它比 Map
的 List
,但它需要一个额外的依赖,因为Java没有内置这样的类型。
另外,除非你真的想要,否则没有必要自己实现观察者模式。这些都是非常健壮的实现,并且在它的基础上提供了非常好的操作。