- 观察者模式是一种行为设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象发生变化时,它的所有观察者都会收到通知并更新。观察者模式常用于实现事件处理系统、发布-订阅模式等。
- 在项目中,我们使用RabbitMQ、Kafka、ActiveMQ等消息中间件来进行解耦、异步、广播、削峰,在设计模式中我们可以使用观察者模式也能达到解耦、异步的特点。下面我将介绍观察者模式。
观察者模式的主要角色
- Subject(主题):被观察的对象,包含对观察者的引用列表,并提供注册、移除和通知观察者的方法。
- Observer(观察者):定义一个更新接口,用于接收主题的通知。
- ConcreteSubject(具体主题):具体的主题,实现了主题接口,状态发生改变时通知所有注册的观察者。
- ConcreteObserver(具体观察者):具体的观察者,实现了观察者接口,响应主题的变化。
Java 实现观察者模式
下面是一个简单的 Java 观察者模式示例:
1. 定义观察者接口
public interface Observer {void update(String message);// 处理业务逻辑
}
2. 定义主题接口
public interface Subject {void registerObserver(Observer observer);// 添加观察者void removeObserver(Observer observer);// 移除观察者void notifyObservers();// 通知所有观察者事件
}
3. 实现具体主题
public class ConcreteSubject implements Subject{private List<Observer> observers;private String message;public ConcreteSubject() {this.observers = new ArrayList<>();}@Overridepublic void registerObserver(Observer observer) {observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update(message);}}public void setMessage(String message) {this.message = message;notifyObservers();}
}
4. 实现具体观察者
public class ConcreteObserver implements Observer {private String name;public ConcreteObserver(String name) {this.name = name;}// 模拟处理业务逻辑@Overridepublic void update(String message) {System.out.println(name + " received message: " + message);}
}
5.测试
public class ObserverPatternDemo {public static void main(String[] args) {ConcreteSubject subject = new ConcreteSubject();Observer observer1 = new ConcreteObserver("Observer 1");Observer observer2 = new ConcreteObserver("Observer 2");Observer observer3 = new ConcreteObserver("Observer 3");subject.registerObserver(observer1);subject.registerObserver(observer2);subject.registerObserver(observer3);System.out.println("----------------------向三个订阅者发送消息 First Message----------------------");subject.setMessage("First Message");System.out.println("----------------------向三个订阅者发送消息 Second Message----------------------");subject.setMessage("Second Message");System.out.println("----------------------依次一个订阅者并发送消息 Third Message-------------------------");subject.removeObserver(observer2);subject.setMessage("Third Message");}
}
6.结果![image.png](https://img-blog.csdnimg.cn/img_convert/df892013fe743bedcba1ba37de9142b7.png)
7.分析
-
在这里我们可以看到,我们已经可以做到可以向多个订阅者发送消息,而只需要创建一个新的订阅者放入observers容器里面,从而达到解耦的目的。
-
而要达到异步的功能,可以利用java的并发工具,比如线程、“
ExecutorService
”等。下面给出实现思路:
1.使用 ExecutorService:
使用 Executors.newCachedThreadPool() 创建一个可缓存的线程池。可以使用其他类型的线程池,如 FixedThreadPool 或 SingleThreadExecutor,根据具体需求选择。
2.异步通知:
在 notifyObservers 方法中,通过 executorService.submit() 提交任务,使得每个观察者的 update 方法在单独的线程中执行,达到了异步通知的效果。
3.资源管理:
在合适的时候调用 executorService.shutdown() 来关闭线程池,确保资源得到释放。通过这种方式,实现了观察者模式的异步通知,使得观察者的 update 方法可以并发执行,提高了效率,避免了通知过程中阻塞的问题。
观察者模式在框架中的应用
1. Java Swing
Java Swing 中的事件处理模型大量使用了观察者模式。按钮点击、窗口关闭等事件的处理都是通过事件监听器实现的。
2. Spring Framework
Spring 框架中也广泛使用了观察者模式,特别是在事件驱动的编程模型中。
- ApplicationEvent 和 ApplicationListener: Spring 提供了一个事件机制,通过
ApplicationEvent
和ApplicationListener
实现观察者模式。
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;@Component
public class MyApplicationListener implements ApplicationListener<ContextRefreshedEvent> {@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {System.out.println("Context Refreshed Event received!");}
}
public class MyCustomEvent extends ApplicationEvent {public MyCustomEvent(Object source) {super(source);}
}@Component
public class MyCustomEventListener implements ApplicationListener<MyCustomEvent> {@Overridepublic void onApplicationEvent(MyCustomEvent event) {System.out.println("Custom Event received!");}
}// 发布事件
@Component
public class MyBean {private final ApplicationEventPublisher publisher;public MyBean(ApplicationEventPublisher publisher) {this.publisher = publisher;}public void publishEvent() {MyCustomEvent event = new MyCustomEvent(this);publisher.publishEvent(event);}
}
3. Google Guava
Google Guava 提供的 EventBus
是一种实现发布-订阅(Pub/Sub)模式的工具,它的实现也是采用设计模式中的观察者设计模式。,它广泛应用于解耦事件生产者和消费者。在 EventBus
中,事件生产者和事件消费者可以彼此独立地工作,彼此无需直接依赖。
观察者模式的优缺点
优点
- 解耦:观察者和主题之间是抽象耦合的,可以独立扩展观察者和主题。
- 动态订阅:观察者可以在运行时动态添加或移除。
- 灵活性:可以在不修改主题类的情况下增加新的观察者,实现了开闭原则。
缺点
- 可能引起性能问题:如果观察者较多,通知所有观察者可能会比较耗时。
- 可能导致内存泄漏:如果观察者没有及时被移除,可能导致内存泄漏。
使用场景
- 事件处理系统:GUI 事件监听,按钮点击事件。
- 发布-订阅系统:消息队列,订阅推送服务。
- 数据变化通知:数据模型变化通知视图更新,类似于 MVC 模式中的观察者角色