观察者模式(Observer Pattern)

观察者模式(Observer Pattern)

观察者模式是一种行为型设计模式,它定义了对象之间的一对多依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都会自动收到通知并更新。观察者模式也被称为发布-订阅模式,它允许对象之间松耦合地交互。

模式结构

  1. 发布者接口(Publisher)
    定义订阅、取消订阅和通知观察者的方法。
  2. 具体发布者(Concrete Publisher)
    实现发布者接口,负责维护观察者列表,并在状态改变时通知所有观察者。
  3. 观察者接口(Observer)
    定义更新方法,观察者通过该方法接收发布者的通知。
  4. 具体观察者(Concrete Observer)
    实现观察者接口,负责在接收到通知时执行相应的操作。
  5. 客户端(Client)
    创建发布者和观察者对象,并将观察者注册到发布者中。

代码示例

1. 发布者接口(Publisher)

// 发布者接口:定义订阅、取消订阅和通知观察者的方法
interface Publisher {
    void subscribe(Observer observer);
    void unSubscribe(Observer observer);
    void notifySubscribers();
    Object update(Observer observer);
}

2. 具体发布者(Concrete Publisher)

// 具体发布者:实现发布者接口
class MessageCenter implements Publisher {
    private final List<Observer> observers;
    private String message;
    private Boolean changed;
    private final Object SEM = new Object();

    public MessageCenter() {
        this.observers = new ArrayList<>();
    }

    @Override
    public void subscribe(Observer observer) {
        synchronized (SEM) {
            if (!observers.contains(observer)) {
                observers.add(observer);
            }
        }
    }

    @Override
    public void unSubscribe(Observer observer) {
        synchronized (SEM) {
            observers.remove(observer);
        }
    }

    @Override
    public void notifySubscribers() {
        List<Observer> localObservers;
        synchronized (SEM) {
            if (!changed) {
                return;
            }
            localObservers = new ArrayList<>(this.observers);
            this.changed = false;
        }

        for (Observer observer : localObservers) {
            observer.update();
        }
    }

    @Override
    public Object update(Observer observer) {
        return this.message;
    }

    public void postMessage(String message) {
        System.out.println("Message Center Posted : " + message);
        this.message = message;
        this.changed = true;
        notifySubscribers();
    }
}

3. 观察者接口(Observer)

// 观察者接口:定义更新方法
interface Observer {
    void update();
    void bind(Publisher publisher);
}

4. 具体观察者(Concrete Observer)

// 具体观察者:实现观察者接口
class MessageSubscriber implements Observer {
    private String name;
    private Publisher publisher;

    public MessageSubscriber(String name) {
        this.name = name;
    }

    @Override
    public void update() {
        String message = (String) publisher.update(this);
        if (message != null) {
            System.out.println("[" + name + "] Consuming message : " + message);
        } else {
            System.out.println("[" + name + "] No new message");
        }
    }

    @Override
    public void bind(Publisher publisher) {
        this.publisher = publisher;
    }
}

5.调用示例

public class ObserverPattern {
    public static void main(String[] args) {
        MessageCenter messageCenter = new MessageCenter();

        Observer observer1 = new MessageSubscriber("Jack");
        Observer observer2 = new MessageSubscriber("Tom");
        Observer observer3 = new MessageSubscriber("Mike");

        messageCenter.subscribe(observer1);
        messageCenter.subscribe(observer2);
        messageCenter.subscribe(observer3);

        observer1.bind(messageCenter);
        observer2.bind(messageCenter);
        observer3.bind(messageCenter);

        observer1.update();

        messageCenter.postMessage("How are you feeling today?");
    }
}

输出结果

[Jack] No new message
Message Center Posted : How are you feeling today?
[Jack] Consuming message : How are you feeling today?
[Tom] Consuming message : How are you feeling today?
[Mike] Consuming message : How are you feeling today?

应用场景

  1. 一对多的依赖关系
    当一个对象的状态改变需要通知多个其他对象时,可以使用观察者模式。例如,消息发布系统、事件处理系统等。
  2. 动态订阅机制
    当需要在运行时动态地添加或移除观察者时,可以使用观察者模式。观察者模式允许观察者随时加入或离开发布者的订阅列表。
  3. 解耦发布者和观察者
    当需要将发布者和观察者解耦,使得它们可以独立变化时,可以使用观察者模式。

在Java中的应用

  • java.util.Observerjava.util.Observable
    Java 提供了 Observer 接口和 Observable 类来实现观察者模式。尽管这些类在 Java 9 中被标记为过时,但它们仍然是观察者模式的经典实现。
  • 事件监听机制
    Java 的 GUI 框架(如 Swing 和 JavaFX)广泛使用了观察者模式来处理用户事件(如按钮点击、鼠标移动等)。

优缺点

优点

  • 解耦发布者和观察者
    观察者模式将发布者和观察者解耦,使得它们可以独立变化。
  • 动态订阅机制
    观察者模式允许在运行时动态地添加或移除观察者,增加了系统的灵活性。
  • 支持广播通信
    观察者模式支持一对多的通信方式,发布者可以同时通知多个观察者。

缺点

  1. 通知顺序不确定
    观察者模式中,观察者被通知的顺序是不确定的,可能会导致一些难以调试的问题。
  2. 性能问题
    如果观察者数量过多,或者观察者的更新操作非常耗时,可能会导致性能问题。

总结

观察者模式通过定义对象之间的一对多依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都会自动收到通知并更新。它适用于需要解耦发布者和观察者、支持动态订阅机制或广播通信的场景。尽管它可能会带来通知顺序不确定和性能问题,但其优点在于提高了系统的灵活性和可扩展性。在Java中,观察者模式广泛应用于事件处理和GUI框架等场景。