JAVA设计模式之观察者模式

观察者模式是日常开发中最为常用的设计模式之一,本文主要分为四个部分:1、什么是观察者模式 2、观察者模式由哪些组件构成 3、使用观察者模式实现天气预报布告栏的案例 4、使用JDK内置的观察者模式实现天气预报布告栏的案例。

什么是观察者模式

观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象的状态发生改变时,它的所有依赖者都会收到通知,并且做出改变。
在现实生活中,可以找到很多跟观察者模式有关的例子,比如说猎头和求职者之间就是一种一对多的关系,有一个猎头,求职者们可以在他那儿登陆注册,留存简历,当猎头发现有合适的工作时会将应聘信息发送给这些人,求职者可以随时跟猎头建立或者取消合作关系,一旦取消合作关系,猎头就不会再发送应聘信息给对应的求职者,这其中猎头就扮演一种有状态的对象,而求职者就是依赖猎头的对象,他们是一对多的关系。
观察者模式-猎头与求职者
观察者模式由哪些组件构成

根据观察者模式的概念,我们很容易想到,观察者模式中的两种核心组件,即主题对象(Subject)和众多的观察者对象(Observer),一旦主题对象中的内容发生改变,观察者也要根据改变的内容对自己做出调整。因此观察者的UML类图可以简单描述为:
观察者模式UML类图
上图中,Subject是一个主题接口,接口中包含注册观察者、移除观察者、通知观察者这三个基本事件,每个具体的主题都应该去实现这个接口,重写其中的方法。Observer是观察者接口,与主题是多对一的关系,观察者的核心方法是update方法,根据主题发生的变化,自动更新自己的状态。

观察者模式实现天气预报布告栏案例

通过一个实际的案例来运用一下观察者模式,一个天气预报发布平台有三种布告栏:

  • 目前天气布告栏
    格式为:今天天气(晴朗/多云/有雨/有雪)
  • 气压温度布告栏
    格式为:今天气压(XX)Pa,温度(XX)摄氏度
  • 明天天气预报布告栏
    格式为:明天天气(晴朗/多云/有雨/有雪)
    这个案例中,我们可以把天气预报的数据看成是主题对象Subject,包含了天气的详细信息,而三个布告栏就是观察者Observers,Subject中天气信息的一旦变更会通知三个布告栏,布告栏调用自己的update方法来更新显示内容,这是一个典型的观察者模式,下面我们就用代码来实现这个案例。

// 主题接口

public interface Subject {
    public void registerObserver(Observer observer);
    public void removeObserver(Observer observer);
    public void notifyObservers();
}

// 布告栏显示接口

// 布告栏信息显示,每个布告栏除了实现Observer接口,还需实现本接口
public interface DisplayElement {
    public void display();
}

// 观察者接口

public interface Observer {
    // 这个方法中的数据,原则上来说应该封装成一个对象,这里为了简单起见直接写死了
    public void update(String todayWeather,Double pa, Double temp, String tomorrowWeather);
}

// 天气数据主题类

import java.util.ArrayList;
import java.util.List;

public class WeatherData implements Subject {
    private List<Observer> observers;
    private String todayWeather;
    private Double pa;
    private Double temp;
    private String tomorrowWeather;
    public WeatherData(){
        observers = new ArrayList<>();
    }
    @Override
    public void registerObserver(Observer observer) {
        // 注册新的观察者
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        int index = observers.indexOf(observer);
        if(index > -1)
            observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        //数据改动时通知各个观察者
        for( Observer o : observers)
            o.update(todayWeather,pa,temp,tomorrowWeather);
    }

    public void dataChanged(){
        notifyObservers();
    }
    public void setNewData(String todayWeather,Double pa, Double temp, String tomorrowWeather){
        this.todayWeather = todayWeather;
        this.pa = pa;
        this.temp = temp;
        this.todayWeather = tomorrowWeather;
        dataChanged();
    }

}

// 温度气压布告栏

public class TempAndPressureBoard implements Observer,DisplayElement{

    private Double pa;
    private Double temp;
    private Subject weatherData;
    public TempAndPressureBoard(Subject weatherData){
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }
    @Override
    public void display() {
        System.out.println("气压温度布告栏------》今天气压"+pa+"Pa,温度"+temp+"摄氏度");
    }

    @Override
    public void update(String todayWeather, Double pa, Double temp, String tomorrowWeather) {
        this.pa = pa;
        this.temp = temp;
        display();
    }
}

// 今天天气布告栏

public class TodayWeatherBoard implements Observer,DisplayElement {
    private String todayWeather;
    private Subject weatherData;

    public TodayWeatherBoard(Subject weatherData){
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }
    @Override
    public void display() {
        System.out.println("今天天气布告栏------》今天天气"+this.todayWeather);
    }

    @Override
    public void update(String todayWeather, Double pa, Double temp, String tomorrowWeather) {
        this.todayWeather = todayWeather;
        display();
    }
}

// 测试类

public class Test {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        TodayWeatherBoard todayBoard = new TodayWeatherBoard(weatherData);
        TempAndPressureBoard tempAndPressureBoard = new TempAndPressureBoard(weatherData);
        weatherData.setNewData("晴朗",5.0,25.0,"晴朗");
        weatherData.setNewData("下雨",4.0,22.0,"下雪");
    }
}

运行结果

采用JDK内置的观察者模式实现天气预报布告栏案例

上面是我们自己动手实现的一个天气预报布告栏的案例,不过自己实现还有几个地方的细节没有处理好:

  1. 上面的观察者更新的数据写死了,无法更改。
  2. 主题对象将所有数据推送给观察者,但是有些数据并不是每个观察者都需要的。那么,主题对象是不是应该只通知观察者数据更新了,而具体需要什么数据,由各个观察者自己去主题对象那边取。
    基于以上两个问题,我们可以做出进一步改进,不过这里就不自己动手写了,我们用JDK中封装好的观察者模式编写改进。

// WeatherData 主题类,继承Observable类

import java.util.Observable;

public class WeatherData extends Observable {
    private String todayWeather;
    private Double pa;
    private Double temp;
    private String tomorrowWeather;


    public void setNewData(String todayWeather,Double pa, Double temp, String tomorrowWeather){
        this.todayWeather = todayWeather;
        this.pa = pa;
        this.temp = temp;
        this.todayWeather = tomorrowWeather;
        setChanged();
        notifyObservers();
    }


    public String getTodayWeather() {
        return todayWeather;
    }

    public void setTodayWeather(String todayWeather) {
        this.todayWeather = todayWeather;
    }

    public Double getPa() {
        return pa;
    }

    public void setPa(Double pa) {
        this.pa = pa;
    }

    public Double getTemp() {
        return temp;
    }

    public void setTemp(Double temp) {
        this.temp = temp;
    }

    public String getTomorrowWeather() {
        return tomorrowWeather;
    }

    public void setTomorrowWeather(String tomorrowWeather) {
        this.tomorrowWeather = tomorrowWeather;
    }
}

// TempAndPressureBoard 布告板

import java.util.Observable;
import java.util.Observer;

public class TempAndPressureBoard implements Observer, DisplayElement{
    private Double pa;
    private Double temp;
    public TempAndPressureBoard(Observable observable){
        observable.addObserver(this);
    }
    @Override
    public void update(Observable o, Object arg) {
       if( o instanceof  WeatherData){
           this.pa = ((WeatherData) o).getPa();
           this.temp = ((WeatherData) o).getTemp();
           display();
       }
    }

    @Override
    public void display() {
        System.out.println("气压温度布告栏------》今天气压"+pa+"Pa,温度"+temp+"摄氏度");
    }
}

// 测试类

public class Test {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        TempAndPressureBoard tempAndPressureBoard = new TempAndPressureBoard(weatherData);
        weatherData.setNewData("晴朗",5.0,25.0,"晴朗");
        weatherData.setNewData("下雨",4.0,22.0,"下雪");
    }
}

运行结果

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Java观察者设计模式是一种一对多的依赖关系,其目标对象维护一组观察者对象,当目标对象的状态发生变化时,它会自动通知并更新所有的观察者对象。这种模式可以使目标对象与观察者对象之间解耦,使它们可以独立地进行修改和重用。 在Java观察者模式已经被封装成了两个接口:目标接口(Observable)和观察者接口(Observer)。目标接口(Observable)定义了添加、删除和通知观察者对象的方法,而观察者接口(Observer)定义了观察者对象接收更新通知方法。 在实际应用,我们可以通过实现观察者接口(Observer)来创建具体的观察者对象,并通过实现目标接口(Observable)来创建具体的目标对象。具体的观察者对象可以订阅目标对象的状态变化,并根据变化做出相应的响应。 在Java观察者模式被广泛应用于各个领域。在Android开发,许多常见的组件和框架都使用了观察者模式,比如OnClickListener、ContentObserver,以及RxJava、RxAndroid和EventBus等通讯库。这些例子都是基于观察者模式的实现,通过观察者模式可以实现组件之间的解耦和灵活的消息传递。 总结来说,Java观察者设计模式是一种实现目标和观察者对象之间解耦的设计模式,它可以提高代码的灵活性和可维护性。在实际应用,我们可以使用Java提供的目标接口(Observable)和观察者接口(Observer)来实现观察者模式,并通过具体的观察者对象订阅目标对象的状态变化。这种设计模式在Android开发也被广泛应用,并带来了许多便利的消息传递和通讯方式。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Java设计模式观察者模式(Observer Pattern)](https://blog.csdn.net/engineer_zh/article/details/78857166)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [java设计模式观察者模式](https://blog.csdn.net/m0_47944994/article/details/127903096)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芒果大柚子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值