1:观察者模式 入门理解
观察者模式(Observer Design Pattern)也被称为发布订阅模式(Publish-Subscribe Design Pattern)。
在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知。
被依赖的对象叫作被观察者(Observable),依赖的对象叫作观察者(Observer)。
也有以下叫法:
Subject-Observer、Publisher-Subscriber、Producer-Consumer、EventEmitter-EventListener、Dispatcher-Listener
2:经典代码流程
1:设置 发布者订阅者 模块方法 Observer Subject
2:创建 发布者订阅者 实现类 ConcreteSubject ConcreteObserver
3:订阅者 注册到发布者上 表示监听发布者
4:给发布者发送消息 然后监听该发布者的所有订阅者 都能收到
1:发布者 与 订阅者 抽象类
public interface Publisher {
//注册订阅者
void registerObserver(Observer observer);
//移除订阅者
void removeObserver(Observer observer);
//给所有发布者发布消息
void notifyObserversSuccess(String message);
//一次性注册所有发布者(可以不用
void registerAllObserver(List<Observer> observers);
}
public interface Observer {
void success(String message);
}
2:发布者 与 订阅者 实现类
public class ConcretePublisher implements Publisher {
private List<Observer> observers = new ArrayList();
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
// 同步阻塞
@Override
public void notifyObserversSuccess(String message) {
for (Observer observer : observers) {
observer.success(message);
}
}
@Override
public void registerAllObserver(List<Observer> observers) {
this.observers = observers;
}
}
// ConcreteObserverOne ConcreteObserverTwo ConcreteObserverRemove (重复3次 修改类名为以下即可)
public class ConcreteObserver implements Observer{
@Override
public void success(String message) {
//可以根据 发布者的消息 执行自己的逻辑
System.out.println("ConcreteObserver is success." + message);
}
}
3:调用者
//一个个进行订阅者进行新增
private static void testObserverAdd() {
ConcretePublisher subject = new ConcretePublisher();
subject.registerObserver(new ConcreteObserverOne());
subject.registerObserver(new ConcreteObserverTwo());
ConcreteObserverRemove concreteObserverRemove = new ConcreteObserverRemove();
subject.registerObserver(concreteObserverRemove);
subject.removeObserver(concreteObserverRemove);
subject.notifyObserversSuccess("ObserverAdd 成功了");
}
//一次性注册全部订阅者
private static void testObserverAll() {
ConcretePublisher subject = new ConcretePublisher();
List<Observer> observers = new ArrayList<>();
observers.add(new ConcreteObserverOne());
observers.add(new ConcreteObserverTwo());
ConcreteObserverRemove concreteObserverRemove = new ConcreteObserverRemove();
observers.add(concreteObserverRemove);
subject.registerAllObserver(observers);
subject.removeObserver(concreteObserverRemove);
subject.notifyObserversSuccess("ObserverAll 成功了");
}
3:基于不同应用场景的不同实现方式
观察者模式的应用场景非常广泛,小到代码层面的解耦,大到架构层面的系统解耦,再或者一些产品的设计思路,
都有这种模式的影子,比如,邮件订阅、RSS Feeds(站点共享),本质上都是观察者模式。
应对于普通的请求:
同步阻塞的实现方式:发布者和订阅者代码在同一个线程内执行,
发布者一直阻塞,直到所有的订阅者代码都执行完成之后,才执行后续的代码。
应对于频繁的请求:
异步非阻塞的实现方式:
方法1:在订阅者的方法中,使用一个新的线程执行代码
方法2:基于 EventBus 来实现
了解:
如果还需要请求第三方平台(即进程外),那么还可以沿用上面的逻辑,或者用一种更优雅的方式:
基于消息队列实现(解耦更彻底),但增加了维护成本
4:同步阻塞 和 异步非阻塞 对比
// 同步阻塞
@Override
public void notifyObserversSuccess(String message) {
for (Observer observer : observers) {
observer.success(message);
}
}
// 异步非阻塞 新增线程
@Override
public void notifyObserversSuccess(String message) {
for (Observer observer : observers) {
Thread thread = new Thread(() -> {
observer.success(message);
});
thread.start();
}
}
// 创建线程池
private static ThreadPoolExecutor threadPoolExecutor =
new ThreadPoolExecutor(4, 4, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1024));
// 异步非阻塞 新增线程池
@Override
public void notifyObserversSuccess(String message) {
for (Observer observer : observers) {
threadPoolExecutor.execute(() -> observer.success(message));
}
}
第一种实现方式,频繁地创建和销毁线程比较耗时,并且并发线程数无法控制,创建过多的线程会导致堆栈溢出。
第二种实现方式,尽管利用了线程池解决了第一种实现方式的问题,但线程池、异步执行逻辑都耦合在了方法里了。
5:遗留问题
如果我们的需求更加极端一点,需要在同步阻塞和异步非阻塞之间灵活切换,那就要不停地修改 发布者类的代码
除此之外,如果在项目中,不止一个业务模块需要用到异步非阻塞观察者模式,那这样的代码实现也无法做到复用。
因此我们引入EventBus 框架
项目连接
请配合项目代码食用效果更佳:
项目地址:
https://github.com/hesuijin/hesujin-design-pattern
Git下载地址:
https://github.com.cnpmjs.org/hesuijin/hesujin-design-pattern.git
demo-study模块 下 behavior_design_pattern observer包