观察者模式的定义

观察者模式(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 编程中,当用户点击按钮、输入文本等操作发生时,会触发相应的事件。这些事件可以看作是主题,而处理这些事件的代码则可以看作是观察者。当事件发生时,系统会通知所有注册的观察者进行相应的处理。
  • 消息通知系统:例如,社交平台上用户发布新动态时,关注该用户的其他用户会收到通知。这里,发布动态的用户是主题,关注者是观察者,当有新动态发布时,关注者会收到通知。
  • 股票价格监控系统:股票价格的变化可以看作是主题的状态变化,而股民或金融机构可以看作是观察者。当股票价格发生变化时,观察者会收到通知并进行相应的操作。
  • 系统日志记录:在大型系统中,某些关键操作的状态变化(如数据库操作、文件读写等)可以作为主题,日志记录器作为观察者。当关键操作的状态发生变化时,日志记录器会记录相应的信息。