本文目录导读:

我将为您提供几个Java观察者模式的案例,从基础到进阶。
基础案例:天气站
这是最经典的观察者模式例子。
import java.util.ArrayList;
import java.util.List;
// 观察者接口
interface Observer {
void update(float temperature, float humidity, float pressure);
}
// 主题接口
interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 具体主题:天气数据
class WeatherData implements Subject {
private List<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
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(temperature, humidity, pressure);
}
}
// 当数据变化时调用
public void measurementsChanged() {
notifyObservers();
}
// 模拟数据变化
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
}
// 具体观察者1:当前条件显示
class CurrentConditionsDisplay implements Observer {
private float temperature;
private float humidity;
@Override
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
display();
}
public void display() {
System.out.println("当前条件: " + temperature + "°C, " + humidity + "% 湿度");
}
}
// 具体观察者2:统计显示
class StatisticsDisplay implements Observer {
private float maxTemp = 0;
private float minTemp = 200;
private float tempSum = 0;
private int numReadings = 0;
@Override
public void update(float temperature, float humidity, float pressure) {
tempSum += temperature;
numReadings++;
if (temperature > maxTemp) maxTemp = temperature;
if (temperature < minTemp) minTemp = temperature;
display();
}
public void display() {
System.out.println("统计结果: " + (tempSum / numReadings)
+ " 平均温度, " + maxTemp + " 最高温度, " + minTemp + " 最低温度");
}
}
// 测试类
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay();
StatisticsDisplay statisticsDisplay = new StatisticsDisplay();
weatherData.registerObserver(currentDisplay);
weatherData.registerObserver(statisticsDisplay);
System.out.println("=== 第一次更新 ===");
weatherData.setMeasurements(25.5f, 65, 1013.2f);
System.out.println("\n=== 第二次更新 ===");
weatherData.setMeasurements(26.8f, 70, 1014.5f);
// 移除一个观察者
weatherData.removeObserver(statisticsDisplay);
System.out.println("\n=== 第三次更新 (移除统计显示后) ===");
weatherData.setMeasurements(24.2f, 68, 1012.8f);
}
}
进阶案例:消息通知系统
使用Lambda表达式和函数式接口简化实现。
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
// 事件类型
enum EventType {
NEW_MESSAGE,
FRIEND_REQUEST,
SYSTEM_ALERT
}
// 事件类
class Event {
private EventType type;
private String message;
private Object data;
public Event(EventType type, String message, Object data) {
this.type = type;
this.message = message;
this.data = data;
}
public EventType getType() { return type; }
public String getMessage() { return message; }
public Object getData() { return data; }
}
// 事件总线
class EventBus {
private static EventBus instance;
private List<Consumer<Event>> listeners = new ArrayList<>();
private EventBus() {}
public static EventBus getInstance() {
if (instance == null) {
instance = new EventBus();
}
return instance;
}
public void subscribe(Consumer<Event> listener) {
listeners.add(listener);
}
public void unsubscribe(Consumer<Event> listener) {
listeners.remove(listener);
}
public void publish(Event event) {
listeners.forEach(listener -> {
try {
listener.accept(event);
} catch (Exception e) {
System.err.println("处理事件时出错: " + e.getMessage());
}
});
}
}
// 消息服务
class MessagingService {
private List<String> users = new ArrayList<>();
public void sendMessage(String user, String message) {
Event event = new Event(EventType.NEW_MESSAGE,
"用户 " + user + " 发送了消息: " + message, user);
EventBus.getInstance().publish(event);
}
public void addUser(String username) {
users.add(username);
Event event = new Event(EventType.SYSTEM_ALERT,
"新用户加入: " + username, username);
EventBus.getInstance().publish(event);
}
}
// 客户端示例
public class EventSystemDemo {
public static void main(String[] args) {
EventBus eventBus = EventBus.getInstance();
// UI组件1:聊天界面
eventBus.subscribe(event -> {
if (event.getType() == EventType.NEW_MESSAGE) {
System.out.println("[聊天界面] 收到新消息: " + event.getMessage());
}
});
// UI组件2:系统通知栏
eventBus.subscribe(event -> {
if (event.getType() == EventType.SYSTEM_ALERT) {
System.out.println("[通知栏] !! 系统通知: " + event.getMessage());
}
});
// 使用Lambda表达式注册观察者
eventBus.subscribe(event -> {
if (event.getType() == EventType.NEW_MESSAGE) {
System.out.println("[日志记录] 记录消息: " + event.getMessage());
}
});
// 测试
MessagingService service = new MessagingService();
System.out.println("=== 添加用户 ===");
service.addUser("张三");
System.out.println("\n=== 发送消息 ===");
service.sendMessage("张三", "大家好!");
System.out.println("\n=== 再发送一条消息 ===");
service.sendMessage("李四", "晚上好");
}
}
完整的企业级案例:股票监控系统
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
// 观察者模式结合传统实现和现代特性
// 股票类
class Stock {
private String symbol;
private double price;
public Stock(String symbol, double price) {
this.symbol = symbol;
this.price = price;
}
public String getSymbol() { return symbol; }
public double getPrice() { return price; }
@Override
public String toString() {
return symbol + " $" + price;
}
}
// 股票市场(主题)
class StockMarket {
private Map<String, Double> stocks = new HashMap<>();
private List<StockObserver> observers = new CopyOnWriteArrayList<>();
public interface StockObserver {
void onPriceChange(Stock stock);
}
public void registerObserver(StockObserver observer) {
observers.add(observer);
}
public void unregisterObserver(StockObserver observer) {
observers.remove(observer);
}
public void addStock(Stock stock) {
stocks.put(stock.getSymbol(), stock.getPrice());
notifyObservers(stock);
}
public void updatePrice(String symbol, double newPrice) {
Double currentPrice = stocks.get(symbol);
if (currentPrice != null && currentPrice != newPrice) {
stocks.put(symbol, newPrice);
Stock stock = new Stock(symbol, newPrice);
notifyObservers(stock);
}
}
private void notifyObservers(Stock stock) {
observers.forEach(observer -> observer.onPriceChange(stock));
}
}
// 具体观察者:个人投资者
class Investor implements StockMarket.StockObserver {
private String name;
private Set<String> monitoredStocks;
private double threshold; // 价格阈值
public Investor(String name, double threshold, String... monitoredStocks) {
this.name = name;
this.threshold = threshold;
this.monitoredStocks = new HashSet<>(Arrays.asList(monitoredStocks));
}
@Override
public void onPriceChange(Stock stock) {
if (monitoredStocks.contains(stock.getSymbol())) {
double change = Math.abs(stock.getPrice() - threshold);
if (change > threshold * 0.1) { // 超过10%的波动
System.out.println(name + " 注意: " + stock + " 波动较大!");
} else {
System.out.println(name + " 收到通知: " + stock + " 价格已更新");
}
}
}
}
// 具体观察者:量化交易机器人
class TradingBot implements StockMarket.StockObserver {
private String botName;
private List<String> tradableStocks;
private boolean autoTrade = true;
public TradingBot(String botName, List<String> tradableStocks) {
this.botName = botName;
this.tradableStocks = tradableStocks;
}
@Override
public void onPriceChange(Stock stock) {
if (tradableStocks.contains(stock.getSymbol())) {
if (stock.getPrice() > 100) {
System.out.println("[交易机器人 " + botName + "] 建议买入 " + stock);
} else if (stock.getPrice() < 50) {
System.out.println("[交易机器人 " + botName + "] 建议卖出 " + stock);
} else {
System.out.println("[交易机器人 " + botName + "] 价格平稳,不操作");
}
}
}
}
// 主体测试
public class StockMarketDemo {
public static void main(String[] args) {
StockMarket market = new StockMarket();
// 创建观察者
Investor alice = new Investor("Alice", 100, "AAPL", "GOOGL");
Investor bob = new Investor("Bob", 50, "MSFT");
TradingBot bot1 = new TradingBot("Bot-1", Arrays.asList("AAPL", "MSFT"));
// 注册观察者
market.registerObserver(alice);
market.registerObserver(bob);
market.registerObserver(bot1);
// 模拟股票变化
System.out.println("=== 添加新股票 ===");
market.addStock(new Stock("AAPL", 150.0));
System.out.println("\n=== 更新股票价格 ===");
market.updatePrice("AAPL", 160.0);
market.updatePrice("GOOGL", 2500.0);
market.updatePrice("MSFT", 45.0);
market.updatePrice("TSLA", 700.0);
// 取消注册
market.unregisterObserver(bob);
System.out.println("\n=== 更新价格(Bob已取消注册)===");
market.updatePrice("MSFT", 55.0);
market.updatePrice("AAPL", 165.0);
// 显示当前状态
System.out.println("\n=== 最终状态 ===");
// 这里没有直接访问内部Map的方法,可以添加
}
}
关键要点
观察者模式的四大角色
- Subject(主题): 维护观察者列表,发送通知
- ConcreteSubject(具体主题): 存储状态,状态变化时通知观察者
- Observer(观察者): 定义更新接口
- ConcreteObserver(具体观察者): 实现更新逻辑
实现方式
- 传统方式: 使用接口和类
- Lambda方式: 使用函数式接口简化代码
- 事件总线: 解耦生产者与消费者
应用场景
- GUI事件监听
- 消息推送系统
- 日志记录系统
- 缓存同步
- 实时数据监控
优点
- 解耦,主题和观察者松耦合
- 支持广播通信
- 易于扩展
缺点
- 通知顺序不可控
- 可能导致性能问题(大量观察者)
- 循环依赖风险
性能优化建议
- 使用CopyOnWriteArrayList避免并发问题
- 使用java.util.Observer接口(已过时,建议自定义)
- 考虑批量处理和异步通知
这些案例展示了观察者模式在不同场景下的应用,从简单的天气站到复杂的事件驱动系统,选择哪种实现取决于您的具体需求。