观察者模式 (Observer Pattern)
代码示例:
git clone https://gitee.com/qq1244811434/23DesignPatterns.git
优点
- 实现对象间解耦
- 支持广播通信,灵活性高
- 动态添加/移除观察者
缺点
- 可能引发通知链,调试困难
- 观察者过多时影响性能
特点
- 一对多依赖关系
- 主题与观察者解耦
- 支持动态注册和移除观察者
应用场景
- 事件处理系统
- 消息推送系统
- 股票价格变化通知
测试
/**
* 演示观察者模式
*/
@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:


1万+

被折叠的 条评论
为什么被折叠?



