自学内容网 自学内容网

【设计模式】观察者模式 在java中的应用

引言

观察者模式的定义

观察者模式(Observer Pattern)是一种行为设计模式,它定义了对象之间的一对多依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。这种模式通常用于实现事件处理系统。

通过观察者模式,主题(Subject)和观察者(Observer)之间的耦合度降低了。主题只需维护一个观察者列表,并负责通知观察者,而不需要关心观察者的具体实现。

观察者模式的应用场景

观察者模式广泛应用于需要事件通知的场景,以下是一些典型的应用场景:

  1. GUI框架中的事件处理

    • 在图形用户界面(GUI)中,按钮、文本框等控件的事件处理通常使用观察者模式。例如,按钮的点击事件可以通知多个监听器执行相应的操作。
  2. 数据模型与视图的同步

    • 在MVC(Model-View-Controller)架构中,模型(Model)是主题,视图(View)是观察者。当模型的数据发生变化时,视图需要自动更新以反映最新的数据。
  3. 发布-订阅系统

    • 在消息系统中,发布者(Publisher)和订阅者(Subscriber)之间通常使用观察者模式。发布者发布消息,所有订阅了该消息的订阅者都会收到通知并处理消息。
  4. 日志系统

    • 在日志系统中,可以将不同的日志记录器(如文件记录器、控制台记录器)作为观察者,日志事件发生时,所有的日志记录器都会收到通知并记录日志。

观察者模式的基本概念

主题(Subject)和观察者(Observer)的关系

在观察者模式中,主要涉及两个角色:主题(Subject)和观察者(Observer)。

  1. 主题(Subject)

    • 主题是被观察的对象。它维护了一组观察者,并在自身状态发生变化时通知这些观察者。
    • 主题通常提供以下方法:
      • registerObserver(Observer o):注册一个观察者。
      • removeObserver(Observer o):移除一个观察者。
      • notifyObservers():通知所有注册的观察者。
  2. 观察者(Observer)

    • 观察者是观察主题的对象。当主题的状态发生变化时,观察者会收到通知并进行相应的更新。
    • 观察者通常实现一个update方法,用于接收主题的通知并更新自身状态。

观察者模式的优缺点

优点
  1. 解耦

    • 观察者模式将观察者与主题解耦,使得它们可以独立变化。主题不需要知道观察者的具体实现,只需通过接口进行通知。
  2. 灵活性

    • 可以在运行时动态添加或移除观察者,增强了系统的灵活性和可扩展性。
  3. 符合开闭原则

    • 观察者模式使得系统易于扩展。当需要增加新的观察者时,不需要修改现有的主题代码,只需实现新的观察者并注册到主题中即可。
缺点
  1. 可能导致性能问题

    • 当观察者数量较多时,通知所有观察者可能会导致性能问题。尤其是在观察者需要处理复杂逻辑时,整个通知过程可能会变得很慢。
  2. 可能导致内存泄漏

    • 如果主题维护的观察者列表没有及时清理(例如,观察者已经不再需要但没有被移除),可能会导致内存泄漏。
  3. 不确定的通知顺序

    • 通常情况下,观察者的通知顺序是不确定的。如果不同的观察者对通知的顺序有依赖性,可能会导致问题。

Java中的观察者模式实现

Java内置的观察者模式

Java 提供了一套内置的观察者模式实现,通过 java.util.Observer 接口和 java.util.Observable 类来实现。

java.util.Observer 接口

Observer 接口只有一个方法,需要观察者实现:

public interface Observer {
    void update(Observable o, Object arg);
}
java.util.Observable

Observable 类提供了一些方法来管理和通知观察者:

public class Observable {
    // 添加观察者
    public synchronized void addObserver(Observer o) { ... }

    // 删除观察者
    public synchronized void deleteObserver(Observer o) { ... }

    // 通知所有观察者
    public void notifyObservers() { ... }

    // 通知所有观察者,并传递参数
    public void notifyObservers(Object arg) { ... }

    // 标记状态已改变
    protected synchronized void setChanged() { ... }

    // 清除已改变标记
    protected synchronized void clearChanged() { ... }

    // 检查状态是否已改变
    public synchronized boolean hasChanged() { ... }

    // 获取观察者数量
    public synchronized int countObservers() { ... }
}
示例代码
import java.util.Observable;
import java.util.Observer;

// 具体的主题类
class WeatherData extends Observable {
    private float temperature;
    private float humidity;
    private float pressure;

    public void measurementsChanged() {
        setChanged();
        notifyObservers();
    }

    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }

    public float getTemperature() {
        return temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    public float getPressure() {
        return pressure;
    }
}

// 具体的观察者类
class CurrentConditionsDisplay implements Observer {
    private float temperature;
    private float humidity;

    public CurrentConditionsDisplay(Observable observable) {
        observable.addObserver(this);
    }

    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof WeatherData) {
            WeatherData weatherData = (WeatherData) o;
            this.temperature = weatherData.getTemperature();
            this.humidity = weatherData.getHumidity();
            display();
        }
    }

    public void display() {
        System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
    }
}

// 测试代码
public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();

        CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);

        weatherData.setMeasurements(80, 65, 30.4f);
        weatherData.setMeasurements(82, 70, 29.2f);
    }
}

自定义实现观察者模式

虽然 Java 内置的观察者模式实现已经很方便,但有时我们需要自定义实现以满足特定需求。以下是一个自定义实现的示例:

自定义接口和类
import java.util.ArrayList;
import java.util.List;

// 观察者接口
interface Observer {
    void update(float temperature, float humidity, float pressure);
}

// 主题接口
interface Subject {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    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 o) {
        observers.add(o);
    }

    @Override
    public void removeObserver(Observer o) {
        observers.remove(o);
    }

    @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();
    }
}

// 具体的观察者类
class CurrentConditionsDisplay implements Observer {
    private float temperature;
    private float humidity;

    public CurrentConditionsDisplay(Subject weatherData) {
        weatherData.registerObserver(this);
    }

    @Override
    public void update(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        display();
    }

    public void display() {
        System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
    }
}

// 测试代码
public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();

        CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);

        weatherData.setMeasurements(80, 65, 30.4f);
        weatherData.setMeasurements(82, 70, 29.2f);
    }
}

具体代码示例

使用 java.util.Observerjava.util.Observable 的示例

首先,我们来看一个使用 Java 内置的 ObserverObservable 来实现观察者模式的示例。

主题类(Observable)
import java.util.Observable;

public class WeatherData extends Observable {
    private float temperature;
    private float humidity;
    private float pressure;

    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }

    public void measurementsChanged() {
        setChanged();
        notifyObservers();
    }

    public float getTemperature() {
        return temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    public float getPressure() {
        return pressure;
    }
}
观察者类(Observer)
import java.util.Observable;
import java.util.Observer;

public class CurrentConditionsDisplay implements Observer {
    private float temperature;
    private float humidity;

    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof WeatherData) {
            WeatherData weatherData = (WeatherData) o;
            this.temperature = weatherData.getTemperature();
            this.humidity = weatherData.getHumidity();
            display();
        }
    }

    public void display() {
        System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
    }
}
测试类
public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay();
        
        weatherData.addObserver(currentDisplay);

        weatherData.setMeasurements(80, 65, 30.4f);
        weatherData.setMeasurements(82, 70, 29.2f);
        weatherData.setMeasurements(78, 90, 29.2f);
    }
}

自定义实现观察者模式的示例

接下来,我们来看一个自定义实现观察者模式的示例。

主题接口
import java.util.ArrayList;
import java.util.List;

public interface Subject {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers();
}
观察者接口
public interface Observer {
    void update(float temperature, float humidity, float pressure);
}
具体的主题实现类
public 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 o) {
        observers.add(o);
    }

    @Override
    public void removeObserver(Observer o) {
        observers.remove(o);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(temperature, humidity, pressure);
        }
    }

    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }

    public void measurementsChanged() {
        notifyObservers();
    }
}
具体的观察者实现类
public 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("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
    }
}
测试类
public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay();
        
        weatherData.registerObserver(currentDisplay);

        weatherData.setMeasurements(80, 65, 30.4f);
        weatherData.setMeasurements(82, 70, 29.2f);
        weatherData.setMeasurements(78, 90, 29.2f);
    }
}

通过这两个示例,我们可以看到如何使用 Java 内置的 ObserverObservable 实现观察者模式,以及如何自定义实现观察者模式。

观察者模式在实际项目中的应用

典型应用场景

观察者模式在实际项目中有许多典型的应用场景,包括但不限于:

  1. 事件处理系统:在 GUI 工具包(如 Java Swing)中,观察者模式用于监听用户事件(如按钮点击、文本输入等)。
  2. 日志系统:在应用程序中,日志记录器可以作为观察者,监听应用程序的状态变化并记录相关信息。
  3. 通知系统:在社交网络、邮件系统或消息推送系统中,观察者模式用于通知用户关于某些事件的发生。
  4. 数据同步:在分布式系统中,观察者模式用于保证数据的一致性,当数据发生变化时,所有的副本都会同步更新。

观察者模式在 MVC 架构中的应用

MVC(Model-View-Controller)架构是一个非常经典的设计模式,广泛应用于各种软件开发中。观察者模式在 MVC 架构中扮演了重要角色,特别是在 Model 和 View 之间的交互中。

MVC 架构概述
  • Model:负责数据和业务逻辑的处理。
  • View:负责数据显示和用户界面的呈现。
  • Controller:负责接收用户输入并调用 Model 和 View 来完成用户请求。

在 MVC 中,Model 作为主题(Subject),View 作为观察者(Observer)。当 Model 中的数据发生变化时,View 会自动更新,以反映新的数据状态。

示例代码

我们以一个简单的股票价格更新系统为例,展示观察者模式在 MVC 架构中的应用。

Model 类
import java.util.Observable;

public class StockData extends Observable {
    private String stockSymbol;
    private float stockPrice;

    public StockData(String stockSymbol) {
        this.stockSymbol = stockSymbol;
    }

    public void setStockPrice(float stockPrice) {
        this.stockPrice = stockPrice;
        stockPriceChanged();
    }

    public void stockPriceChanged() {
        setChanged();
        notifyObservers();
    }

    public String getStockSymbol() {
        return stockSymbol;
    }

    public float getStockPrice() {
        return stockPrice;
    }
}
View 类
import java.util.Observable;
import java.util.Observer;

public class StockDisplay implements Observer {
    private Observable stockData;
    private String stockSymbol;
    private float stockPrice;

    public StockDisplay(Observable stockData) {
        this.stockData = stockData;
        stockData.addObserver(this);
    }

    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof StockData) {
            StockData stockData = (StockData) o;
            this.stockSymbol = stockData.getStockSymbol();
            this.stockPrice = stockData.getStockPrice();
            display();
        }
    }

    public void display() {
        System.out.println("Stock: " + stockSymbol + " Price: " + stockPrice);
    }
}
Controller 类
public class StockController {
    private StockData stockData;

    public StockController(StockData stockData) {
        this.stockData = stockData;
    }

    public void updateStockPrice(float newPrice) {
        stockData.setStockPrice(newPrice);
    }
}
测试代码
public class StockMarket {
    public static void main(String[] args) {
        StockData stockData = new StockData("AAPL");
        StockDisplay stockDisplay = new StockDisplay(stockData);
        StockController stockController = new StockController(stockData);

        stockController.updateStockPrice(150.0f);
        stockController.updateStockPrice(155.0f);
    }
}

小结

观察者模式的优缺点总结

优点
  1. 松耦合:观察者模式使得观察者和主题之间的耦合度降低。主题不需要知道观察者的具体实现,只需要知道它们实现了观察者接口。
  2. 灵活性:可以在运行时动态添加和移除观察者,提供了很大的灵活性。
  3. 扩展性:可以很容易地添加新的观察者而不影响现有的系统。
  4. 一致性:当主题的状态发生变化时,所有的观察者都会自动接收到通知,保持数据的一致性。
缺点
  1. 性能开销:如果有大量的观察者,通知所有观察者可能会影响性能。
  2. 复杂性增加:管理观察者列表和通知机制会增加系统的复杂性,特别是在处理并发问题时。
  3. 潜在的内存泄漏:如果观察者没有正确地解除注册,可能会导致内存泄漏。

使用观察者模式的最佳实践

  1. 明确职责:确保主题和观察者各自的职责明确,主题只负责状态的管理和通知,观察者负责响应和处理通知。
  2. 避免过度使用:不要滥用观察者模式,尤其是在简单的场景中。过度使用会增加系统的复杂性。
  3. 处理并发问题:在多线程环境中,确保对观察者列表的操作是线程安全的,以避免并发问题。
  4. 解除注册:在适当的时候(如观察者不再需要接收通知时)确保观察者正确地解除注册,以避免内存泄漏。
  5. 通知优化:在大量观察者的情况下,可以考虑批量通知或延迟通知,以优化性能。

原文地址:https://blog.csdn.net/qq_42320804/article/details/144332740

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!