观察者模式 (Observer Pattern)

文章目录

观察者模式 (Observer Pattern)

观察者模式 是一种 行为型设计模式 ,用于定义对象间的一种 一对多 依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都会收到通知并自动更新。


原理

  1. 核心思想
    • 当目标对象(Subject)发生变化时,通知所有观察者(Observer)。
    • 将目标与观察者之间的依赖关系分离,使得两者可以独立变化。
  2. 适用场景
    • 一个对象的变化需要通知其他对象。
    • 不希望目标对象和观察者之间存在紧耦合关系。
  3. 参与角色
    • Subject(目标/被观察者)
      • 保存观察者对象的列表。
      • 提供注册、移除观察者的方法。
      • 当状态发生改变时,通知所有观察者。
    • Observer(观察者)
      • 提供更新接口,供目标调用。
    • ConcreteSubject(具体目标)
      • 实现具体的状态逻辑。
    • ConcreteObserver(具体观察者)
      • 实现更新接口,定义具体更新行为。

优点

  1. 解耦:观察者和目标分离,可以独立扩展。
  2. 动态响应:目标状态变化时,观察者可以动态收到通知。
  3. 复用性强:观察者模式非常灵活,适用于各种场景。

缺点

  1. 通知机制复杂性:通知过程可能产生较高的时间开销。
  2. 可能出现循环依赖:当观察者也会触发目标变化时,需防止死循环。
  3. 难以控制通知顺序:观察者的调用顺序由实现决定。

示例代码

场景描述

以新闻发布系统为例,新闻发布者是目标,订阅用户是观察者。当新闻发布时,所有订阅用户都会收到通知。


1. 定义观察者接口
java 复制代码
// 观察者接口
public interface Observer {
    void update(String message); // 接收目标的更新通知
}

2. 定义目标接口
java 复制代码
// 目标接口
public interface Subject {
    void registerObserver(Observer observer); // 注册观察者
    void removeObserver(Observer observer);   // 移除观察者
    void notifyObservers();                   // 通知所有观察者
}

3. 实现具体目标类
java 复制代码
import java.util.ArrayList;
import java.util.List;

// 具体目标类
public class NewsPublisher implements Subject {
    private List<Observer> observers; // 保存观察者列表
    private String news;              // 新闻内容

    public NewsPublisher() {
        observers = new ArrayList<>();
    }

    @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(news); // 通知每个观察者
        }
    }

    // 更新新闻并通知观察者
    public void setNews(String news) {
        this.news = news;
        notifyObservers();
    }
}

4. 实现具体观察者类
java 复制代码
// 具体观察者
public class Subscriber implements Observer {
    private String name;

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

    @Override
    public void update(String message) {
        System.out.println(name + " received news: " + message);
    }
}

5. 客户端代码
java 复制代码
public class ObserverPatternExample {
    public static void main(String[] args) {
        NewsPublisher publisher = new NewsPublisher();

        // 创建观察者
        Observer alice = new Subscriber("Alice");
        Observer bob = new Subscriber("Bob");
        Observer charlie = new Subscriber("Charlie");

        // 注册观察者
        publisher.registerObserver(alice);
        publisher.registerObserver(bob);

        // 发布新闻
        publisher.setNews("Breaking News: Observer Pattern Explained!");

        // 移除观察者
        publisher.removeObserver(alice);

        // 再次发布新闻
        publisher.setNews("Update: Observer Pattern is Easy!");
    }
}

输出结果
text 复制代码
Alice received news: Breaking News: Observer Pattern Explained!
Bob received news: Breaking News: Observer Pattern Explained!
Bob received news: Update: Observer Pattern is Easy!

UML 类图

        +------------------+
        |    Subject       |<-------------------+
        +------------------+                    |
        | + registerObserver()|                 |
        | + removeObserver()  |                 |
        | + notifyObservers() |                 |
        +------------------+                    |
                ^                               |
                |                               |
+-----------------------+       +-----------------------+
|   NewsPublisher       |       |       Observer        |
+-----------------------+       +-----------------------+
| - observers : List    |       | + update(message)     |
| + setNews(news)       |       +-----------------------+
| + notifyObservers()   |                 ^
+-----------------------+                 |
                |                         |
       +-----------------------+   +-----------------------+
       |      Subscriber        |   |      Subscriber        |
       +-----------------------+   +-----------------------+
       | - name : String        |   | - name : String        |
       | + update(message)      |   | + update(message)      |
       +-----------------------+   +-----------------------+

使用场景

  1. 事件监听:GUI 开发中,按钮点击事件的监听。
  2. 消息订阅:发布/订阅模式,如 RabbitMQ、Kafka。
  3. 实时更新:如股票价格、天气更新。

优化与扩展

  1. 使用 Java 内置类
    • Java 提供了 Observable 类和 Observer 接口。
    • Observable 已被标记为过时,推荐自定义实现。
  2. 多线程支持
    • 使用线程安全的集合 CopyOnWriteArrayList 避免并发问题。
  3. 结合其他模式
    • 中介者模式 结合,简化复杂的观察者关系。

小结

  • 观察者模式在事件驱动系统中非常常用。
  • 它解耦了目标和观察者,但需要注意性能问题。
  • 可结合其他模式(如工厂模式)简化观察者的管理和创建。
相关推荐
春风十里不如你952720 小时前
【设计模式】【行为型模式(Behavioral Patterns)】之观察者模式(Observer Pattern)
观察者模式·设计模式
请你打开电视看看1 天前
观察者模式
java·观察者模式·设计模式
loey_ln2 天前
观察者模式和发布订阅模式
javascript·观察者模式·react.js
你好helloworld2 天前
设计模式之观察者模式
观察者模式·设计模式
zzzhpzhpzzz4 天前
设计模式——观察者模式
算法·观察者模式·设计模式
小白不太白9505 天前
设计模式之 观察者模式
观察者模式·设计模式
蓝田~5 天前
观察者模式和订阅模式
windows·观察者模式
Mr. zhihao9 天前
从业务场景学习观察者模式
学习·观察者模式
Mr. zhihao9 天前
观察者模式 vs 不使用观察者模式:商品库存变化的通知
java·观察者模式