23种设计模式之四:观察者模式

观察者模式 (Observer Pattern)

代码示例:

git clone https://gitee.com/qq1244811434/23DesignPatterns.git

优点

  1. 实现对象间解耦
  2. 支持广播通信,灵活性高
  3. 动态添加/移除观察者

缺点

  1. 可能引发通知链,调试困难
  2. 观察者过多时影响性能

特点

  1. 一对多依赖关系
  2. 主题与观察者解耦
  3. 支持动态注册和移除观察者

 应用场景

  1. 事件处理系统
  2. 消息推送系统
  3. 股票价格变化通知

测试

    /**
     * 演示观察者模式
     */
    @GetMapping("/observer")
    public Map<String, Object> demonstrateObserver() {
        Map<String, Object> result = new HashMap<>();
        result.put("pattern", "观察者模式");
        result.put("description", "定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象");
        
        // 执行观察者模式演示
        observerPattern.demonstrateObserverPattern();
        
        result.put("message", "观察者模式演示完成,请查看控制台输出");
        return result;
    }

输出结果:

{
    "pattern": "观察者模式",
    "description": "定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象",
    "message": "观察者模式演示完成,请查看控制台输出"
}

控制台输出内容:
=== 新闻发布观察者模式演示 ===
观察者 张三 已注册
观察者 李四 已注册
观察者 王五 已注册
发布新闻: 重大新闻:Spring Boot 3.0 正式发布!
张三 收到通知: 重大新闻:Spring Boot 3.0 正式发布!
李四 收到通知: 重大新闻:Spring Boot 3.0 正式发布!
王五 收到通知: 重大新闻:Spring Boot 3.0 正式发布!
观察者 李四 已移除
发布新闻: 技术更新:Java 17 成为新的LTS版本
张三 收到通知: 技术更新:Java 17 成为新的LTS版本
王五 收到通知: 技术更新:Java 17 成为新的LTS版本

=== 股票价格观察者模式演示 ===
股票观察者 投资者A 已注册
股票观察者 投资者B 已注册
股票观察者 投资者C 已注册
投资者A 收到股票价格变化通知: 股票价格从 100.00 变为 110.00,上涨了 10.00
投资者B 收到股票价格变化通知: 股票价格从 100.00 变为 110.00,上涨了 10.00
投资者C 收到股票价格变化通知: 股票价格从 100.00 变为 110.00,上涨了 10.00
投资者A 收到股票价格变化通知: 股票价格从 110.00 变为 105.00,下跌了 5.00
投资者B 收到股票价格变化通知: 股票价格从 110.00 变为 105.00,下跌了 5.00
投资者C 收到股票价格变化通知: 股票价格从 110.00 变为 105.00,下跌了 5.00
投资者A 收到股票价格变化通知: 股票价格从 105.00 变为 120.00,上涨了 15.00
投资者B 收到股票价格变化通知: 股票价格从 105.00 变为 120.00,上涨了 15.00
投资者C 收到股票价格变化通知: 股票价格从 105.00 变为 120.00,上涨了 15.00

完整代码

package com.example.patterns.observer;

import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;

/**
 * 观察者模式演示
 * 
 * 观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。
 * 当主题对象发生变化时,它的所有依赖者(观察者)都会收到通知并自动更新。
 * 
 * 应用场景:
 * - 事件处理系统
 * - 消息推送系统
 * - 股票价格变化通知
 * - 用户状态变化通知
 */
@Component
public class ObserverPattern {

    /**
     * 观察者接口 - 定义观察者的共同行为
     * 抽象观察者,具体观察者需要实现此接口
     */
    public interface Observer {
        /**
         * 更新方法,当被观察者状态改变时调用
         * 
         * @param message 更新消息
         */
        void update(String message);
        
        /**
         * 获取观察者名称
         * 
         * @return 观察者名称
         */
        String getObserverName();
    }

    /**
     * 具体观察者A
     */
    public static class ConcreteObserverA implements Observer {
        private String name;

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

        @Override
        public void update(String message) {
            System.out.println(name + " 收到通知: " + message);
        }

        @Override
        public String getObserverName() {
            return name;
        }
    }

    /**
     * 具体观察者B
     */
    public static class ConcreteObserverB implements Observer {
        private String name;

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

        @Override
        public void update(String message) {
            System.out.println(name + " 收到通知: " + message);
        }

        @Override
        public String getObserverName() {
            return name;
        }
    }

    /**
     * 主题接口 - 被观察者即目标对象。
     * 当被改变时,将通知所有观察者
     * 抽象主题,所有具体主题需要实现此接口
     * 可以有多个观察者。当主题被改变时,通知其所有观察者
     */
    public interface Subject {
        /**
         * 注册观察者
         * 
         * @param observer 观察者
         */
        void registerObserver(Observer observer);

        /**
         * 移除观察者
         * 
         * @param observer 观察者
         */
        void removeObserver(Observer observer);

        /**
         * 通知所有观察者
         * 
         * @param message 通知消息
         */
        void notifyObservers(String message);
    }

    /**
     * 具体主题 - 新闻发布者
     */
    public static class NewsPublisher implements Subject {
        private List<Observer> observers = new ArrayList<>();
        private String news;

        @Override
        public void registerObserver(Observer observer) {
            if (!observers.contains(observer)) {
                observers.add(observer);
                System.out.println("观察者 " + observer.getObserverName() + " 已注册");
            }
        }

        @Override
        public void removeObserver(Observer observer) {
            observers.remove(observer);
            System.out.println("观察者 " + observer.getObserverName() + " 已移除");
        }

        @Override
        public void notifyObservers(String message) {
            System.out.println("发布新闻: " + message);
            for (Observer observer : observers) {
                observer.update(message);
            }
        }

        /**
         * 发布新闻
         * 
         * @param news 新闻内容
         */
        public void publishNews(String news) {
            this.news = news;
            notifyObservers(news);
        }

        public String getNews() {
            return news;
        }
    }

    /**
     * 股票价格观察者模式演示
     */
    public static class StockPriceSubject implements Subject {
        private List<Observer> observers = new ArrayList<>();
        private double price;

        public StockPriceSubject(double initialPrice) {
            this.price = initialPrice;
        }

        @Override
        public void registerObserver(Observer observer) {
            if (!observers.contains(observer)) {
                observers.add(observer);
                System.out.println("股票观察者 " + observer.getObserverName() + " 已注册");
            }
        }

        @Override
        public void removeObserver(Observer observer) {
            observers.remove(observer);
            System.out.println("股票观察者 " + observer.getObserverName() + " 已移除");
        }

        @Override
        public void notifyObservers(String message) {
            for (Observer observer : observers) {
                observer.update(message);
            }
        }

        /**
         * 更新股票价格
         * 
         * @param newPrice 新价格
         */
        public void setPrice(double newPrice) {
            double oldPrice = this.price;
            this.price = newPrice;
            
            String change = newPrice > oldPrice ? "上涨" : "下跌";
            double changeAmount = Math.abs(newPrice - oldPrice);
            String message = String.format("股票价格从 %.2f 变为 %.2f,%s了 %.2f", 
                oldPrice, newPrice, change, changeAmount);
            
            notifyObservers(message);
        }

        public double getPrice() {
            return price;
        }
    }

    /**
     * 股票投资者观察者
     */
    public static class StockInvestor implements Observer {
        private String name;
        private double buyPrice;

        public StockInvestor(String name, double buyPrice) {
            this.name = name;
            this.buyPrice = buyPrice;
        }

        @Override
        public void update(String message) {
            System.out.println(name + " 收到股票价格变化通知: " + message);
            // 这里可以添加投资决策逻辑
        }

        @Override
        public String getObserverName() {
            return name;
        }
    }

    /**
     * 演示观察者模式的使用
     */
    public void demonstrateObserverPattern() {
        System.out.println("=== 新闻发布观察者模式演示 ===");
        
        // 创建主题(新闻发布者)
        NewsPublisher publisher = new NewsPublisher();
        
        // 创建观察者(新闻订阅者)
        // 观察者之间没有联系,可以更便于进行系统拓展符合开闭原则
        Observer observer1 = new ConcreteObserverA("张三");
        Observer observer2 = new ConcreteObserverB("李四");
        Observer observer3 = new ConcreteObserverA("王五");
        
        // 注册观察者
        publisher.registerObserver(observer1);
        publisher.registerObserver(observer2);
        publisher.registerObserver(observer3);
        
        // 发布新闻
        //目标对象被改变,依赖于此的对象即观察者123都将接收到通知
        //观察者模式只能通知观察者目标发生了变化,无法得知如何发生变化
        publisher.publishNews("重大新闻:Spring Boot 3.0 正式发布!");
        
        // 移除一个观察者
        publisher.removeObserver(observer2);
        
        // 再次发布新闻
        publisher.publishNews("技术更新:Java 17 成为新的LTS版本");

        System.out.println("\n=== 股票价格观察者模式演示 ===");
        
        // 创建股票价格主题
        StockPriceSubject stockSubject = new StockPriceSubject(100.0);
        
        // 创建股票投资者观察者
        Observer investor1 = new StockInvestor("投资者A", 95.0);
        Observer investor2 = new StockInvestor("投资者B", 105.0);
        Observer investor3 = new StockInvestor("投资者C", 100.0);
        
        // 注册投资者
        stockSubject.registerObserver(investor1);
        stockSubject.registerObserver(investor2);
        stockSubject.registerObserver(investor3);
        
        // 模拟股票价格变化即目标对象被改变时观察者接收到通知
        // 可以修改setprice方法,将价格具体变化原因细节告知给各个观察者
        stockSubject.setPrice(110.0);  // 价格上涨
        stockSubject.setPrice(105.0);  // 价格下跌
        stockSubject.setPrice(120.0);  // 价格大幅上涨
    }
} 

UML:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值