• 观察者模式


    观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,允许一个对象(称为主题或被观察者)通知多个其他对象(称为观察者)自己的状态变化,从而使观察者能够自动更新。

    观察者模式的核心思想是将主题与观察者解耦,使主题可以独立变化而不影响观察者,同时使观察者可以自动获取主题的更新信息。这种模式有助于构建松耦合的系统,其中对象之间的关系是动态的。

    结构

    观察者模式的主要参与者包括:

    1. 主题(Subject):主题是被观察的对象,它维护一组观察者对象,并提供方法来添加、删除和通知观察者。主题的状态变化会触发通知给观察者。
    2. 观察者(Observer):观察者是依赖于主题的对象,它定义了一个更新接口,通常包括一个 update() 方法,当主题状态变化时,观察者会调用这个方法以执行相应的操作。
    3. 具体主题(Concrete Subject):具体主题是主题的具体实现类,它维护了一个状态,并在状态变化时通知观察者。具体主题负责管理观察者的注册和通知。
    4. 具体观察者(Concrete Observer):具体观察者是观察者的具体实现类,它实现了观察者接口,并定义了在接收到主题通知时要执行的具体操作。

    示例

    下面是另一个示例,演示观察者模式的应用。在这个示例中,将创建一个简单的气象站,气象站会定期测量温度、湿度和气压,并通知多个观察者。

    import java.util.ArrayList;
    import java.util.List;
    // 主题接口
    interface Subject {
        void registerObserver(Observer observer);
        void removeObserver(Observer observer);
        void notifyObservers();
    }
    
    // 具体主题
    class WeatherStation implements Subject {
        private List<Observer> observers = new ArrayList<>();
        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() {
            notifyObservers();
        }
    	
        // 添加订阅者(观察者对象)
        @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);
            }
        }
    }
    
    // 观察者接口
    interface Observer {
        void update(float temperature, float humidity, float pressure);
    }
    
    // 具体观察者
    class Display implements Observer {
        private String name;
    
        public Display(String name) {
            this.name = name;
        }
    
        @Override
        public void update(float temperature, float humidity, float pressure) {
            System.out.println(name + " 收到更新:温度 " + temperature + "°C, 湿度 " + humidity + "%, 气压 " + pressure + " hPa");
        }
    }
    
    public class Client {
        public static void main(String[] args) {
            // 创建气象站
            WeatherStation weatherStation = new WeatherStation();
    
            // 创建观察者
            Observer display1 = new Display("显示器1");
            Observer display2 = new Display("显示器2");
    
            // 注册观察者
            weatherStation.registerObserver(display1);
            weatherStation.registerObserver(display2);
    
            // 模拟气象数据更新
            weatherStation.setMeasurements(25.5f, 60.0f, 1013.2f);
            System.out.println("-------------------------------------------------");
            weatherStation.setMeasurements(27.5f, 65.0f, 1190.3f);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86

    在这个示例中,创建了一个气象站 WeatherStation 作为主题,它可以测量温度、湿度和气压,并在数据发生变化时通知观察者。观察者 Display 可以订阅气象站的通知,并在数据更新时执行相应的操作。

    当气象数据发生变化时,气象站会调用 notifyObservers() 方法通知所有注册的观察者,观察者将更新并输出相应的信息。

    运行示例代码后,可以看到两个观察者收到了气象数据的更新通知,并输出了相应的信息,这演示了观察者模式的应用,其中主题与观察者之间实现了松耦合,主题的状态变化会自动通知观察者。这种模式非常适用于需要实现发布-订阅机制的场景

    优点

    观察者模式具有多个优点,使其成为一种有用的设计模式,适用于许多不同的应用场景。以下是观察者模式的主要优点:

    1. 松耦合: 观察者模式实现了主题与观察者之间的松耦合关系。主题和观察者之间互不依赖,主题只知道它们的接口,不需要了解观察者的具体实现,反之亦然。这使得系统更加灵活和易于维护。
    2. 可扩展性: 观察者模式支持动态添加和删除观察者,而不需要修改主题的代码。这使得系统更容易扩展,可以随时添加新的观察者来响应主题的事件。
    3. 多播通知: 主题可以同时通知多个观察者,观察者之间互相独立。这意味着多个观察者可以同时响应同一事件,而不会相互干扰。
    4. 分离关注点: 观察者模式分离了关注主题状态变化的代码和实际业务逻辑。这使得主题的状态变化不会影响业务逻辑,提高了代码的可维护性和可读性。
    5. 定制化通知: 观察者可以根据需要实现自定义的更新逻辑。不同的观察者可以对相同的事件做出不同的响应,从而适应不同的业务需求。
    6. 开闭原则: 观察者模式符合开闭原则,因为可以在不修改现有代码的情况下引入新的观察者和主题类。这有助于系统的可维护性和可扩展性。
    7. 实现事件处理: 观察者模式是实现事件驱动编程的一种常见方式。它允许主题对象通知观察者对象有关事件的发生,观察者对象可以根据事件来执行相应的操作。
    8. 降低耦合性: 观察者模式降低了对象之间的耦合性,因为主题和观察者之间的连接是动态的,可以在运行时建立和解除连接。

    缺点

    尽管观察者模式具有许多优点,但也存在一些缺点和考虑事项:

    1. 可能引发性能问题: 在观察者模式中,主题对象的状态变化会通知所有观察者对象,如果观察者数量较多或观察者的更新操作较复杂,可能会引发性能问题。因此,在高性能要求的应用中,需要谨慎使用观察者模式,并考虑优化方案。
    2. 可能导致循环依赖: 如果观察者之间相互依赖,可能会导致循环依赖的问题。这样的循环依赖可能会导致不稳定的行为,需要谨慎设计观察者之间的关系。
    3. 可能需要额外的内存空间: 每个观察者对象需要注册到主题对象中,这可能会占用额外的内存空间,特别是在观察者数量较多时。如果内存占用是一个问题,需要考虑其他方案。
    4. 通知顺序不确定性: 观察者收到通知的顺序是不确定的,这可能导致观察者之间的竞争条件或不一致性。如果需要确定的通知顺序,观察者模式可能不是最佳选择。
    5. 可能引发异常问题: 如果观察者的 update 方法中出现异常,可能会影响到其他观察者的通知,甚至导致主题对象无法正常工作。因此,在观察者模式中,需要确保观察者的 update 方法是健壮的。
    6. 过多的细粒度: 使用过多的观察者可能导致系统中存在大量细粒度的类,增加了代码的复杂性。需要权衡观察者的数量和系统的复杂性。

    适用场景

    观察者模式适用于以下场景:

    1. 一对多的依赖关系: 当一个对象的状态变化需要通知多个其他对象,并且这些对象之间的关系是一对多的关系时,观察者模式非常适用。例如,当一个主题对象的状态变化需要通知多个观察者对象时,可以使用观察者模式。

    2. 对象状态与行为分离: 当需要确保主题对象(被观察者)的状态变化不影响其他对象的行为时,观察者模式是一种有效的方式。观察者模式将状态和行为分离,使得主题对象和观察者对象互不干扰。

    3. 动态更新: 当对象的状态可能经常变化,并且其他对象需要在状态变化时自动更新时,观察者模式非常有用。这有助于实现实时的事件处理和动态数据更新。

    4. 解耦和分布式系统: 观察者模式有助于解耦系统中的组件,使得各个组件之间的依赖关系降低。这对于构建分布式系统和松耦合的系统非常重要。

    5. 事件处理系统: 观察者模式是事件驱动编程的一种常见实现方式。例如,在图形用户界面(GUI)开发中,各种用户交互事件可以作为主题,而界面元素可以作为观察者,以响应事件并更新界面。

    6. 消息通知系统: 消息通知系统通常需要将消息发布给多个订阅者,这可以通过观察者模式来实现。发布者是主题,而订阅者是观察者,它们可以订阅感兴趣的消息并在消息发布时接收通知。

    7. 数据监控和报告生成: 当需要监控数据源的状态变化并生成报告或执行其他操作时,观察者模式可以用于实现数据监控和自动报告生成。

    总的来说,观察者模式适用于需要实现发布-订阅机制、对象状态变化通知多个对象、松耦合和动态更新的各种应用场景。它有助于构建灵活、可扩展、可维护的系统,同时降低了对象之间的耦合性。

    源码解析

    在 Java 中,观察者模式被广泛应用,并且在 Java 标准库中有多个实现。

    其中,最常见的就是 Java 的事件处理机制和 java.util 包中的观察者模式实现。

    让我们来看一下 java.util 包中的观察者模式的应用,主要集中在 ObservableObserver 类中。

    1. Observable 类: java.util.Observable 是 Java 标准库中的一个类,它表示可以被观察的对象,即主题对象。这个类提供了一组方法来管理观察者和通知观察者对象。

      • addObserver(Observer o):用于向主题对象添加观察者。
      • deleteObserver(Observer o):用于从主题对象中删除观察者。
      • deleteObservers():用于删除所有观察者。
      • setChanged():标记主题对象的状态已经改变。
      • clearChanged():清除主题对象的状态改变标记。
      • hasChanged():检查主题对象的状态是否已经改变。
      • countObservers():获取已注册的观察者数量。
      • notifyObservers():通知所有观察者,它会调用观察者的 update 方法。
    2. Observer 接口: java.util.Observer 是 Java 标准库中的接口,表示观察者对象。观察者需要实现这个接口,并通过 update 方法来响应主题对象的状态变化。

      void update(Observable o, Object arg);
      
      • 1

      update 方法被调用时,它会接收两个参数:o 表示被观察的对象(主题),arg 表示可选的参数,通常用于传递额外的信息。

    下面是一个简单的示例,演示如何在 Java 中使用 ObservableObserver 来实现观察者模式:

    import java.util.Observable;
    import java.util.Observer;
    
    // 具体主题类
    class WeatherData extends Observable {
        private float temperature;
    
        public void setTemperature(float temperature) {
            this.temperature = temperature;
            setChanged(); // 标记状态已经改变
            notifyObservers(); // 通知观察者
        }
    
        public float getTemperature() {
            return temperature;
        }
    }
    
    // 具体观察者类
    class WeatherObserver implements Observer {
        private String name;
    
        public WeatherObserver(String name) {
            this.name = name;
        }
    
        @Override
        public void update(Observable o, Object arg) {
            if (o instanceof WeatherData) {
                WeatherData weatherData = (WeatherData) o;
                float temperature = weatherData.getTemperature();
                System.out.println(name + " 收到更新,温度为: " + temperature + "°C");
            }
        }
    }
    
    public class Client {
        public static void main(String[] args) {
            WeatherData weatherData = new WeatherData();
            
            WeatherObserver observer1 = new WeatherObserver("观察者1");
            WeatherObserver observer2 = new WeatherObserver("观察者2");
    
            weatherData.addObserver(observer1);
            weatherData.addObserver(observer2);
    
            weatherData.setTemperature(25.5f);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    在这个示例中,WeatherData 类是具体的主题类,继承了 Observable,它可以被观察,并在温度变化时通知观察者。WeatherObserver 类是具体的观察者类,实现了 Observer 接口,它会在 update 方法中响应主题的通知。

    总的来说,Java 的 ObservableObserver 提供了一种标准的观察者模式实现,它可以用于许多不同的应用场景,如事件处理、GUI 编程等。当需要实现观察者模式时,可以考虑使用这些标准库中提供的类和接口。

  • 相关阅读:
    CSS样式
    基于JavaWeb的小区物业管理系统的设计与实现
    Codeforces Round #821 (Div. 2)
    英飞凌--GTM架构-Generic Timer Module
    9.19数电——触发器&状态机&第四周作业题解&计数器(部分)
    zookeeper概述
    【python】Django——templates模板、静态文件、django模板语法、请求和响应
    opencv鼠标操作与响应
    Selenium - 自动化测试框架
    Redis之布隆过滤器(Bloom Filter)解读
  • 原文地址:https://blog.csdn.net/qq_73574147/article/details/136460041