观察者模式的定义
观察者模式(Observer Pattern)是一种行为设计模式,它定义了对象之间的一对多依赖关系,当一个对象(被观察对象,也称为主题或可观察对象)的状态发生变化时,所有依赖它的对象(观察者对象)都会收到通知并自动更新。这种模式使得对象之间的交互更加松散,提高了系统的可维护性和可扩展性。
实现方式
1. 自定义实现
以下是一个简单的 Java 代码示例,展示了如何自定义实现观察者模式:
import java.util.ArrayList;
import java.util.List;
// 定义观察者接口
interface Observer {
void update(String message);
}
// 定义主题接口
interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 具体主题类
class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
private String message;
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(message);
}
}
public void setMessage(String message) {
this.message = message;
notifyObservers();
}
}
// 具体观察者类
class ConcreteObserver implements Observer {
private String name;
public ConcreteObserver(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + " 收到消息: " + message);
}
}
// 测试代码
public class ObserverPatternExample {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
ConcreteObserver observer1 = new ConcreteObserver("观察者1");
ConcreteObserver observer2 = new ConcreteObserver("观察者2");
subject.registerObserver(observer1);
subject.registerObserver(observer2);
subject.setMessage("主题状态发生了变化");
}
}
代码解释:
Observer
接口定义了观察者的更新方法update
,当主题状态变化时,会调用该方法通知观察者。Subject
接口定义了主题的三个方法:registerObserver
用于注册观察者,removeObserver
用于移除观察者,notifyObservers
用于通知所有注册的观察者。ConcreteSubject
类实现了Subject
接口,维护了一个观察者列表,并在状态变化时调用notifyObservers
方法通知所有观察者。ConcreteObserver
类实现了Observer
接口,在update
方法中处理收到的通知。
2. 使用 Java 内置的 Observable
类和 Observer
接口(Java 9 之前)
在 Java 9 之前,Java 提供了 java.util.Observable
类和 java.util.Observer
接口来实现观察者模式。不过,Observable
类是一个具体类,存在一些设计上的问题,在 Java 9 中已被标记为过时。
import java.util.Observable;
import java.util.Observer;
// 具体主题类
class ConcreteSubject extends Observable {
private String message;
public void setMessage(String message) {
this.message = message;
setChanged(); // 标记状态已改变
notifyObservers(message); // 通知观察者
}
}
// 具体观察者类
class ConcreteObserver implements Observer {
private String name;
public ConcreteObserver(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
String message = (String) arg;
System.out.println(name + " 收到消息: " + message);
}
}
// 测试代码
public class BuiltInObserverPatternExample {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
ConcreteObserver observer1 = new ConcreteObserver("观察者1");
ConcreteObserver observer2 = new ConcreteObserver("观察者2");
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.setMessage("主题状态发生了变化");
}
}
3. 使用 Reactive Streams(JAVA 9及以上版本)
Reactive Streams 是 Java 中用于响应式编程的规范,提供了一种处理异步数据流的方式,非常适合实现观察者模式。Java 9 引入了 java.util.concurrent.Flow
类,它是 Reactive Streams 规范的 Java 实现。以下是一个简单示例:
import java.util.concurrent.Flow;
import java.util.concurrent.SubmissionPublisher;
// 自定义订阅者
class MySubscriber implements Flow.Subscriber<String> {
private Flow.Subscription subscription;
@Override
public void onSubscribe(Flow.Subscription subscription) {
this.subscription = subscription;
subscription.request(1);
}
@Override
public void onNext(String item) {
System.out.println("收到数据: " + item);
subscription.request(1);
}
@Override
public void onError(Throwable throwable) {
throwable.printStackTrace();
}
@Override
public void onComplete() {
System.out.println("处理完成");
}
}
// 测试代码
public class ReactiveStreamsExample {
public static void main(String[] args) {
// 创建发布者
SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
// 创建订阅者
MySubscriber subscriber = new MySubscriber();
// 订阅
publisher.subscribe(subscriber);
// 发布数据
publisher.submit("数据1");
publisher.submit("数据2");
// 关闭发布者
publisher.close();
}
}
在这个示例中,SubmissionPublisher
充当主题(发布者),MySubscriber
充当观察者(订阅者)。当发布者发布新数据时,订阅者会收到通知并进行处理。Reactive Streams 还支持背压机制,能够更好地处理异步数据流的生产和消费。
4. 使用第三方库
一些第三方库也提供了强大的观察者模式实现,例如 RxJava 和 Project Reactor。这些库提供了丰富的操作符和工具,能够更方便地处理异步和响应式编程。以 RxJava 为例:
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.Observer;
import io.reactivex.rxjava3.disposables.Disposable;
// 测试代码
public class RxJavaExample {
public static void main(String[] args) {
// 创建可观察对象
Observable<String> observable = Observable.just("数据1", "数据2");
// 创建观察者
Observer<String> observer = new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
System.out.println("订阅开始");
}
@Override
public void onNext(String s) {
System.out.println("收到数据: " + s);
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
}
@Override
public void onComplete() {
System.out.println("处理完成");
}
};
// 订阅
observable.subscribe(observer);
}
}
需要注意的是,使用第三方库需要在项目中添加相应的依赖。例如,如果使用 RxJava,需要在 Maven 项目的 pom.xml
中添加以下依赖:
<dependency>
<groupId>io.reactivex.rxjava3</groupId>
<artifactId>rxjava</artifactId>
<version>3.1.5</version>
</dependency>
应用场景
- 事件处理系统:在 GUI 编程中,当用户点击按钮、输入文本等操作发生时,会触发相应的事件。这些事件可以看作是主题,而处理这些事件的代码则可以看作是观察者。当事件发生时,系统会通知所有注册的观察者进行相应的处理。
- 消息通知系统:例如,社交平台上用户发布新动态时,关注该用户的其他用户会收到通知。这里,发布动态的用户是主题,关注者是观察者,当有新动态发布时,关注者会收到通知。
- 股票价格监控系统:股票价格的变化可以看作是主题的状态变化,而股民或金融机构可以看作是观察者。当股票价格发生变化时,观察者会收到通知并进行相应的操作。
- 系统日志记录:在大型系统中,某些关键操作的状态变化(如数据库操作、文件读写等)可以作为主题,日志记录器作为观察者。当关键操作的状态发生变化时,日志记录器会记录相应的信息。