Skip to content

观察者

更新: 6/28/2025 字数: 0 字 时长: 0 分钟

定义

观察者模式 (Observer Pattern) 定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。这种模式又称发布 - 订阅模式,是事件驱动编程的核心模式。

角色

  • 主题 (Subject):维护观察者列表,提供注册/注销接口,状态变化时通知观察者
  • 具体主题 (ConcreteSubject):实现主题接口,存储具体状态
  • 观察者 (Observer):定义更新接口
  • 具体观察者 (ConcreteObserver):实现更新接口,维护对主题的引用
  • 客户端 (Client):创建主题和观察者对象并建立订阅关系

实现

新闻发布系统

java
// 主题接口
public interface NewsPublisher {
    void registerSubscriber(Subscriber subscriber);
    void removeSubscriber(Subscriber subscriber);
    void notifySubscribers();
}

// 具体主题
public class TechNewsPublisher implements NewsPublisher {
    private List<Subscriber> subscribers = new ArrayList<>();
    private String latestNews;
    
    public void publishNews(String news) {
        this.latestNews = news;
        notifySubscribers();
    }
    
    @Override
    public void registerSubscriber(Subscriber subscriber) {
        subscribers.add(subscriber);
    }
    
    @Override
    public void removeSubscriber(Subscriber subscriber) {
        subscribers.remove(subscriber);
    }
    
    @Override
    public void notifySubscribers() {
        for (Subscriber subscriber : subscribers) {
            subscriber.update(latestNews);
        }
    }
}

// 观察者接口
public interface Subscriber {
    void update(String news);
}

// 具体观察者
public class MobileSubscriber implements Subscriber {
    private String name;
    
    public MobileSubscriber(String name) {
        this.name = name;
    }
    
    @Override
    public void update(String news) {
        System.out.printf("[%s 手机端] 收到新闻:%s%n", name, news);
    }
}

public class EmailSubscriber implements Subscriber {
    private String email;
    
    public EmailSubscriber(String email) {
        this.email = email;
    }
    
    @Override
    public void update(String news) {
        System.out.printf("发送邮件至 %s: %s%n", email, news);
    }
}

// 使用示例
public class NewsDemo {
    public static void main(String[] args) {
        TechNewsPublisher publisher = new TechNewsPublisher();
        
        Subscriber mobileUser = new MobileSubscriber("张三");
        Subscriber emailUser = new EmailSubscriber("lisi@example.com");
        
        publisher.registerSubscriber(mobileUser);
        publisher.registerSubscriber(emailUser);
        
        // 发布新闻
        publisher.publishNews("Java 21 正式发布,引入虚拟线程特性");
        publisher.publishNews("OpenAI 发布 GPT-5 模型");
        
        // 取消订阅
        publisher.removeSubscriber(emailUser);
        publisher.publishNews("量子计算机突破 1000 量子比特");
    }
}

股票交易系统

java
// 股票数据
public class StockData {
    private String symbol;
    private double price;
    private double volume;
    
    public StockData(String symbol, double price, double volume) {
        this.symbol = symbol;
        this.price = price;
        this.volume = volume;
    }
    
    // getters...
}

// 主题接口
public interface StockMarket {
    void addObserver(StockObserver observer);
    void removeObserver(StockObserver observer);
    void notifyObservers();
}

// 具体主题
public class NASDAQ implements StockMarket {
    private List<StockObserver> observers = new ArrayList<>();
    private Map<String, StockData> stocks = new HashMap<>();
    
    public void updateStock(String symbol, double price, double volume) {
        stocks.put(symbol, new StockData(symbol, price, volume));
        notifyObservers();
    }
    
    @Override
    public void addObserver(StockObserver observer) {
        observers.add(observer);
    }
    
    @Override
    public void removeObserver(StockObserver observer) {
        observers.remove(observer);
    }
    
    @Override
    public void notifyObservers() {
        for (StockObserver observer : observers) {
            observer.update(stocks);
        }
    }
}

// 观察者接口
public interface StockObserver {
    void update(Map<String, StockData> stocks);
}

// 具体观察者
public class Trader implements StockObserver {
    private String name;
    private Set<String> watchList;
    
    public Trader(String name, String... symbols) {
        this.name = name;
        this.watchList = new HashSet<>(Arrays.asList(symbols));
    }
    
    @Override
    public void update(Map<String, StockData> stocks) {
        System.out.printf("交易员 %s 收到股票更新:%n", name);
        stocks.entrySet().stream()
            .filter(entry -> watchList.contains(entry.getKey()))
            .forEach(entry -> {
                StockData data = entry.getValue();
                System.out.printf("  %s: 价格 %.2f, 成交量 %.2f 万%n", 
                    data.getSymbol(), data.getPrice(), data.getVolume());
            });
    }
}

public class DisplayBoard implements StockObserver {
    @Override
    public void update(Map<String, StockData> stocks) {
        System.out.println("=== 股票行情显示板 ===");
        stocks.values().forEach(data -> 
            System.out.printf("%s: %.2f (%.2f 万手)%n", 
                data.getSymbol(), data.getPrice(), data.getVolume()));
    }
}

// 使用示例
public class StockMarketDemo {
    public static void main(String[] args) {
        NASDAQ nasdaq = new NASDAQ();
        
        StockObserver trader1 = new Trader("王五", "AAPL", "GOOG");
        StockObserver trader2 = new Trader("赵六", "MSFT", "TSLA");
        StockObserver display = new DisplayBoard();
        
        nasdaq.addObserver(trader1);
        nasdaq.addObserver(display);
        
        // 更新股票
        nasdaq.updateStock("AAPL", 175.32, 45.2);
        nasdaq.updateStock("MSFT", 332.15, 32.8);
        
        // 添加新观察者
        nasdaq.addObserver(trader2);
        nasdaq.updateStock("TSLA", 245.67, 78.3);
    }
}

优缺点

优点:

  1. 松耦合设计
  2. 支持广播通信
  3. 遵循开闭原则
  4. 动态订阅关系
  5. 实时通知机制
  6. 支持事件驱动架构

缺点:

  1. 通知顺序不可控
  2. 可能引起循环依赖
  3. 过度通知问题
  4. 内存泄漏风险(观察者未注销)
  5. 调试困难
  6. 性能开销(大量观察者)

应用场景

  1. GUI 事件处理
  2. 消息队列系统
  3. 实时数据监控
  4. 社交媒体通知
  5. 股票行情系统
  6. 游戏引擎事件
  7. 微服务状态同步
  8. 配置中心动态更新

与其他模式的关系

  • 与中介者模式:观察者通过主题协调通信
  • 与责任链模式:可组合实现事件过滤链
  • 与命令模式:观察者触发命令执行
  • 与状态模式:状态变更通知观察者
  • 与代理模式:控制观察者访问权限
  • 与单例模式:主题可能为单例
  • 与发布/订阅模式:观察者是发布/订阅的简化实现

JDK 中的观察者模式

  1. Java AWT/Swing事件监听
  2. Java Beans 属性变更监听
  3. Java.util.Observer/Observable(已弃用)
  4. Java Reactive Streams (Flow API)
  5. Spring ApplicationEvent/Listener
  6. Java EE CDI 事件机制
  7. Java Logging Handler
  8. Java NIO.2 WatchService

注意事项

  1. 避免主题过载(太多观察者)
  2. 处理通知异常(避免影响其他观察者)
  3. 使用弱引用防止内存泄漏
  4. 支持异步通知
  5. 考虑事件去重机制
  6. 设计事件对象携带上下文
  7. 提供优先级机制
  8. 支持过滤订阅

贡献者

The avatar of contributor named as AKAcxp AKAcxp

页面历史