Menu
CoddyTech

观察者模式

本课属于 Coddy Java 学习旅程的“面向对象编程”单元。第 68 课,共 87 课。

观察者模式是一种行为型设计模式,用于建立对象之间的一对多关系。当一个对象(主题)的状态发生变化时,它的所有依赖对象(观察者)都会自动收到通知并更新。你可以把它想象成订阅新闻简报:每当发布新内容时,订阅者都会收到更新。

这种模式包含两个主要部分:主题维护一个观察者列表,并在发生变化时通知它们;观察者则定义一个更新方法来响应通知:

import java.util.ArrayList;
import java.util.List;

interface Observer {
    void update(String message);
}

class NewsPublisher {
    private List<Observer> subscribers = new ArrayList<>();
    
    public void subscribe(Observer observer) {
        subscribers.add(observer);
    }
    
    public void unsubscribe(Observer observer) {
        subscribers.remove(observer);
    }
    
    public void publish(String news) {
        for (Observer subscriber : subscribers) {
            subscriber.update(news);
        }
    }
}

class EmailSubscriber implements Observer {
    private String email;
    
    public EmailSubscriber(String email) {
        this.email = email;
    }
    
    public void update(String message) {
        System.out.println("Email to " + email + ": " + message);
    }
}

发布者发布新闻时,所有订阅者都会自动收到通知:

NewsPublisher publisher = new NewsPublisher();
publisher.subscribe(new EmailSubscriber("alice@mail.com"));
publisher.subscribe(new EmailSubscriber("bob@mail.com"));

publisher.publish("Breaking news!");
// 输出:
// Email to alice@mail.com: Breaking news!
// Email to bob@mail.com: Breaking news!

观察者模式提倡松耦合:主题不需要知道观察者的具体类,只需要知道它们实现了 Observer 接口。这样,你就可以轻松添加新的观察者类型,而无需修改主题。

challenge icon

挑战

简单

让我们使用观察者模式构建一个股价提醒系统!你将创建一个系统,让股票行情器在股价变化时通知多位投资者,每位投资者都可以用自己的方式响应价格更新。

你将把代码分布在四个文件中:

  • Observer.java:定义所有投资者都要实现的 Observer 接口。它应声明一个方法 update(String stockName, double price),观察者通过这个方法接收价格变化通知。
  • StockTicker.java:创建一个主题类,用来维护观察者列表,并在价格变化时通知他们。你的 StockTicker 应包含:

    一个私有的 String 字段,用于保存股票名称(通过构造函数设置)。

    一个私有的 double 字段,用于保存当前价格(初始值为 0)。

    一个私有列表,用于存储已订阅的观察者。

    一个 subscribe(Observer observer) 方法,用于将观察者添加到列表中。

    一个 unsubscribe(Observer observer) 方法,用于从列表中移除观察者。

    一个 setPrice(double price) 方法,用于更新价格,然后调用所有观察者的 update 方法,传入股票名称和新价格,以通知他们。

  • Investors.java:创建两种不同类型的投资者,并让他们实现 Observer 接口:

    DayTrader:有一个通过构造函数设置的私有名称字段。收到更新时,打印 [name] received alert: [stockName] is now $[price] - Making quick trade!

    LongTermInvestor:有一个通过构造函数设置的私有名称字段。收到更新时,打印 [name] received alert: [stockName] is now $[price] - Holding steady.

    将价格格式化为两位小数。

  • Main.java:把观察者系统组合起来!你将接收三个输入:股票名称(String)、第一次价格更新(double)和第二次价格更新(double)。

    使用给定的股票名称创建一个 StockTicker。创建一个名为 "Alice" 的 DayTrader 和一个名为 "Bob" 的 LongTermInvestor,然后让两者都订阅这个行情器。

    将价格设为第一个输入值(所有观察者都会收到通知)。然后取消 Alice 的订阅。最后,将价格设为第二个输入值(这次只通知 Bob)。

你将按顺序接收三个输入:股票名称(String)、第一个价格(double)、第二个价格(double)。

这个挑战展示了观察者模式的优势:StockTicker 不需要了解具体的投资者类型,只需要知道它们实现了 Observer。取消 Alice 的订阅后,她就不会再收到更新,而 Bob 会继续收到通知。这种松散耦合让你可以轻松添加新的投资者类型,而无需修改行情器!

亲手试试

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 读取输入
        String stockName = scanner.nextLine();
        double firstPrice = scanner.nextDouble();
        double secondPrice = scanner.nextDouble();
        
        // TODO: 用给定的股票名称创建一个 StockTicker
        
        // TODO: 创建一个名为 "Alice" 的 DayTrader
        
        // TODO: 创建一个名为 "Bob" 的 LongTermInvestor
        
        // TODO: 让 Alice 和 Bob 都订阅该股票行情
        
        // TODO: 将价格设置为 firstPrice(两个观察者都会收到通知)
        
        // TODO: 取消 Alice 的订阅
        
        // TODO: 将价格设置为 secondPrice(只有 Bob 会收到通知)
        
        scanner.close();
    }
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Java 在线编译器