Java观察者模式案例

wen java案例 1

本文目录导读:

Java观察者模式案例

  1. 基础案例:天气站
  2. 进阶案例:消息通知系统
  3. 完整的企业级案例:股票监控系统
  4. 关键要点

我将为您提供几个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接口(已过时,建议自定义)
  • 考虑批量处理和异步通知

这些案例展示了观察者模式在不同场景下的应用,从简单的天气站到复杂的事件驱动系统,选择哪种实现取决于您的具体需求。

抱歉,评论功能暂时关闭!