java观察者模式之jdk的Observerable的实现

AUTOSAR Dem模块实战配置:从理论到代码生成的完整指南 本文提供了一份AUTOSAR Dem模块从理论到代码生成的完整实战配置指南。文章详细拆解了配置流程,涵盖Dem模块的核心角色、通用骨架搭建、事件与DTC映射、消抖机制配置,以及与BswM、EcuM、DCM等模块的联调方法,旨在帮助汽车电子工程师快速掌握诊断事件管理的关键配置步骤,生成可运行的代码。 阅读详情

概念:

观察者模式:

观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。–>以松耦合的方式在一系列对象之间沟通状态。

上一篇文章用自定义的代码进行了观察者模式的实现,这一篇文章主要讲解jdk的实现方式,并探究此模式在jdk中实现的优缺点:

业务场景:

有一个气象观测站,能够检测具体的气象数据,如温度,湿度和气压,现在有三个具体的显示面板,每当气象数据更新之后,观察者便能够通知到这三个显示面板实时更新数据。这个业务场景刚好符合我们的观察者模式,气象观测站是主题,而显示面板就是观察者。这次通过jdk内置的Observerable来实现业务:
首先是介绍jdk内置的类和接口:

  1. public interface Observer {…}
    观察者需要实现的接口,里面就只有一个update方法,在接收到主题通知的时候进行调用
/*
package java.util;
public interface Observer {
    void update(Observable o, Object arg);
}

  1. public class Observable {…}
    主题需要继承的类,里面的实现并不难。
package java.util;
public class Observable {
    private boolean changed = false;
    private Vector<Observer> obs;//使用线程安全的Vector类来存储观察者
    public Observable() {
        obs = new Vector<>();
    }

	//添加观察者
    public synchronized void addObserver(Observer o) {
        if (o == null)
            throw new NullPointerException();
        if (!obs.contains(o)) {
            obs.addElement(o);
        }
    }
    
   //删除观察者
    public synchronized void deleteObserver(Observer o) {
        obs.removeElement(o);
    }

	//通知观察者,不带参数
    public void notifyObservers() {
        notifyObservers(null);
    }

	//通知观察者,带参数
    public void notifyObservers(Object arg) {
        Object[] arrLocal;

        synchronized (this) {
            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }
	//循环遍历,并且在changed为true的时候才会通知
        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }
 	//删除观察者
    public synchronized void deleteObservers() {
        obs.removeAllElements();
    }
	//改变状态,为true才会通知观察者
    protected synchronized void setChanged() {
        changed = true;
    }
  //清除状态
    protected synchronized void clearChanged() {
        changed = false;
    }
	//返回状态
    public synchronized boolean hasChanged() {
        return changed;
    }
    //获取观察者的数量
    public synchronized int countObservers() {
        return obs.size();
    }
}

可以看出,jdk的实现并不难,主题只要去继承Observable 这个类,并在需要通知的地方,调用setChanged()方法,然后调用notifyObservers()方法即可,而观察者实现Observer 接口,实现自己的update方法就能达到目的。
下面看这个气象案例的实现代码:

  • 具体主题:
package observer.weatherobservable;

import java.util.Observable;

/**
 * 主题,需要继承Observable类
 */
public class WeatherData extends Observable {
    private float temperature;
    private float humidity;
    private float pressure;

    public WeatherData() {

    }

    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;
    }
}
  • 显示面板需要实现的接口:
package observer.weatherobservable;
/**
 * 显示面板需要实现的接口,这个根据具体的场景设计
 */
public interface DisplayElement {
    public void display();
}
  • 当前温度显示面板:
package observer.weatherobservable;

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

/**
 * 当前温度面板
 */
public class CurrentConditionsDisplay implements Observer, DisplayElement {
    private Observable observable;
    private float temperature;
    private float humidity;

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

    @Override
    public void display() {
        System.out.println("当前状态是 " + temperature
                + "华氏度 和 " + 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();
        }
    }
}
  • 预报的显示面板:
package observer.weatherobservable;

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

/**
 * 预报的显示面板
 */
public class ForecastDisplay implements Observer, DisplayElement {
    private float currentPressure = 29.92f;
    private float lastPressure;

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

    @Override
    public void display() {
        System.out.print("预报: ");
        if (currentPressure > lastPressure) {
            System.out.println("温度正在上升!");
        } else if (currentPressure == lastPressure) {
            System.out.println("气温没有变化");
        } else if (currentPressure < lastPressure) {
            System.out.println("天气变冷了");
        }
    }
    
    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof WeatherData) {
            WeatherData weatherData = (WeatherData) o;
            lastPressure = currentPressure;
            currentPressure = weatherData.getPressure();
            display();
        }
    }
}
  • heat index的显示面板:
package observer.weatherobservable;

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

/**
 * heat index的显示面板
 */
public class HeatIndexDisplay implements Observer, DisplayElement {
    float heatIndex = 0.0f;

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

    public void update(Observable observable, Object arg) {
        if (observable instanceof WeatherData) {
            WeatherData weatherData = (WeatherData)observable;
            float t = weatherData.getTemperature();
            float rh = weatherData.getHumidity();
            heatIndex = (float)
                    (
                            (16.923 + (0.185212 * t)) +
                                    (5.37941 * rh) -
                                    (0.100254 * t * rh) +
                                    (0.00941695 * (t * t)) +
                                    (0.00728898 * (rh * rh)) +
                                    (0.000345372 * (t * t * rh)) -
                                    (0.000814971 * (t * rh * rh)) +
                                    (0.0000102102 * (t * t * rh * rh)) -
                                    (0.000038646 * (t * t * t)) +
                                    (0.0000291583 * (rh * rh * rh)) +
                                    (0.00000142721 * (t * t * t * rh)) +
                                    (0.000000197483 * (t * rh * rh * rh)) -
                                    (0.0000000218429 * (t * t * t * rh * rh)) +
                                    (0.000000000843296 * (t * t * rh * rh * rh)) -
                                    (0.0000000000481975 * (t * t * t * rh * rh * rh)));
            display();
        }
    }

    public void display() {
        System.out.println("Heat index 是 " + heatIndex);
    }
}
  • 温度显示面板:
package observer.weatherobservable;

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

/**
 * 溫度顯示面板
 */
public class StatisticsDisplay implements Observer, DisplayElement {
    private float maxTemp = 0.0f;
    private float minTemp = 200;
    private float tempSum= 0.0f;
    private int numReadings;

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

    public void update(Observable observable, Object arg) {
        if (observable instanceof WeatherData) {
            WeatherData weatherData = (WeatherData)observable;
            float temp = weatherData.getTemperature();
            tempSum += temp;
            numReadings++;

            if (temp > maxTemp) {
                maxTemp = temp;
            }

            if (temp < minTemp) {
                minTemp = temp;
            }

            display();
        }
    }

    public void display() {
        System.out.println("Avg/Max/Min temperature = " + (tempSum / numReadings)
                + "/" + maxTemp + "/" + minTemp);
    }
}
  • 测试代码:
package observer.weatherobservable;

/**
 * 測試
 */
public class WeatherStationHeatIndex {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        CurrentConditionsDisplay currentConditions = new CurrentConditionsDisplay(weatherData);//当前状态是
        StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);//Avg/Max/Min
        ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);//预报:
        HeatIndexDisplay heatIndexDisplay = new HeatIndexDisplay(weatherData);//Heat index 是

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

测试结果:
Heat index 是 82.95535
预报: 温度正在上升!
Avg/Max/Min temperature = 80.0/80.0/80.0
当前状态是 80.0华氏度 和 65.0% 湿度
Heat index 是 86.90124
预报: 天气变冷了
Avg/Max/Min temperature = 81.0/82.0/80.0
当前状态是 82.0华氏度 和 70.0% 湿度
Heat index 是 83.64967
预报: 气温没有变化
Avg/Max/Min temperature = 80.0/82.0/78.0
当前状态是 78.0华氏度 和 90.0% 湿度

当然,这个也能都得到我们想要的观察者模式的结果,当气象站检测天气数据变化时,各个显示面板都可以及时显示最新的气象数据.
但是,你会发现,得到的结果和我们添加观察者的顺序不一致,为什么呢?
仔细查看Observer 源码:你会发现它是倒着遍历集合的,哈哈,不知道为什么?
在这里插入图片描述
最后提及下 private boolean changed = false;这个变量的作用,这是为了在需要通知的时候才让我们通知,尽管主题发生了改变,只要这个变量没有更改,我们就无法进行通知。

最后总结下java.util.Observable这个类和Observer接口实现观察者模式的优缺点:

  1. Observer是一个类,所以你必须设计一个类去继承这个类,而java的类是单一继承的,这个限制了我们的设计思路;
  2. Observer的setchanged()是protected的,就是说,你必须在其子类中才能将其进行更改,违反设计原则:多用组合,少用继承;
  3. 通知观察者的方法是在主线程里面顺序执行的,加入哪一个观察者发了阻塞,后续的观察者都要进行等待,非常不友好;
  4. 除了以上的缺点,剩下全是优点。
    鉴于以上的缺点,我们如果要解决上述问题,最后是自定义一个观察者模式的实现,如果可以接受上面的不足之处,我们便可以复用jdk的代码实现了
SerDes系列之 SSC扩频时钟技术 扩频时钟,又称展频(SSC-Spread Spectrum Clocking),当前PCIE、DDR、USB等几乎所有的高速接口都支持SSC的功能。电子工程师在日常的电气测试中经常与之接触,在电磁传导和辐射发射验证过程中,经常需要使用到芯片的SSC功能,它的物理表现形式,就是信号的比特率会在一个很小的范围内浮动,多见于周期性变化的时钟信号。 阅读详情

相关推荐

element的el-cascader组件动态加载,以及报错处理问题

Blocked aria-hidden on an element because its descendant retained focus. The focus must not be hidden from assistive technology users. 报错处理

weixin_56527169的博客 1264

触发链模式之使用jdk的Observable和Observerver实现触发链模式(附JDK源码)

首先看看JDK的Observer接口 public interface Observer { void update(Observable o, Object arg); } 也就一个更新的方法,这里是要写自己要处理事情的逻辑(代码干活的地方) 然后就是Observable类,因为方法过多不好阅读,所以直接看大纲 方法大概就是设置改变状态,设置观察者,通知观察者等等......

five-five 323

基于强化学习的工业SCR脱硝系统控制算法设计与实现

本文提出了一种基于强化学习的工业SCR脱硝系统智能控制方法。针对SCR系统存在的非线性、大滞后和多变量耦合等控制难点,研究采用混合建模方法构建了精度在5%以内的系统模型,并设计了专门的强化学习环境。该方法通过定义合理的动作空间和状态空间,结合物理约束设计损失函数,利用深度强化学习算法优化氨喷射控制策略。相比传统PID控制,该智能控制器能更好地适应烟气参数波动,实现NOx排放的稳定控制,为工业环保设施提供了更优的自动化解决方案。

huanghm88的专栏 1458

深入JDK源码之Observer接口和Observable类实现观察者模式

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34162629的博客 208

RK3568驱动XS9922B:AHD/CVBS双模摄像头兼容性实战

在嵌入式视频开发中,摄像头驱动的稳定性与兼容性往往决定项目交付质量。Linux内核的V4L2框架提供了统一的视频采集抽象,从v4l2_subdev子设备到media controller链路,再到用户态视频节点,每一层都需要精确配置。对于RK3568这类边缘计算平台,其MIPI CSI接口和自研ISP配合RKCIF,构成了完整的多路视频接入通路。当需要接入模拟视频解码芯片时,驱动设计就需同时考虑AHD高清协议与CVBS标清信号的模式切换、格式协商以及寄存器配置。XS9922B作为支持双模输入的解码芯片,可与

weixin_34216614的博客 350

2017阿里内推笔试题--算法工程师(运筹优化)

2017阿里内推笔试题–算法工程师(运筹优化)题目沐哲是一个菜鸟仓库的一个拣货员,但他有非常个怪异的习惯。每次拣货的重量都要比之前拣的一个轻,每次拣到货后都可以得到1块钱,沐哲想知道这样最多能赚多少钱 32 34 7 33 21 2 13 12 3 11 26 36 16 30 22 1 24 14 20 23 25 5 19 29 27 15 9 17 31 4 6 18 8 10 3

shawpan的专栏 1万+

观察者模式(使用JDK内置的工具)

定义:观察者模式(也称发布者/订阅者模式),提供了对象之间的一种依赖关系,当被依赖者发生改变时,它的所有依赖者都会收到通知,并作出反应。 jdk的util包提供了一个类Observable和一个接口Observer。 Observable(被观察者/发布者): 这个类代表一个可观察到的对象,或数据。它可以被细分为代表一个应用程序想要观察的对象。 一个可观察的对象可以有一个或多个观察者。一个...

周先生丶的博客 854

AMBA VIP基础使用方式(AXI)

AXI环境配置 1)基础配置 作为master或者slave使用时,对应的is_active = 1 只作为i监测(monitor)使用时,对应slave_cfg的is_active = 0(对应端口连接也有所区别) class smu_axi_cfg extends svt_axi_system_configuration; `uvm_object_utils(smu_aix_cfg) function new(string name="smu_axi_cfg); super.new(n..

qq_37573794的博客 7984

JDK原生发布订阅 Observer Observable

Observable对象里维护了一个Observer的Vector列表,在this.addObserver()时,会把Observer添加到列表中,值得注意的是添加时会判断是否已存在,判断的依据是Object.equals。使用场景是以单个订阅为主(一个topic对应多个consumer),如果有多个topic则需要创建多个Observable实例,相当于每个topic就是一个WeChat对象。如果想让一个WeChat对象能支持多个topic订阅(实际上是多个tag),则需要二次封装。...

nickDaDa的博客 475

SLG大地图实战:从Tilemap到Shader的地表渲染与数据分层架构

本文深入探讨了SLG大地图开发中的关键技术挑战与解决方案,包括Tilemap系统的深度改造、地表渲染的Shader优化以及数据分层架构设计。通过实战案例,展示了如何实现视觉表现丰富、性能开销可控的SLG大地图,特别适合Unity开发者和游戏技术美术参考。

weixin_28693309的博客 521

ALSA音频开发实战:如何用snd_pcm_avail避免缓冲区溢出(附完整代码)

本文深入探讨了在ALSA音频开发中,如何利用`snd_pcm_avail`函数有效管理环形缓冲区,从而避免音频数据溢出或下溢。通过实战代码示例,详细解析了该函数在播放场景下的核心作用,即实时查询可写入的帧数,并构建了自适应写入循环以实现稳健的流量控制,确保音频流的平滑与稳定。

weixin_29183637的博客 461

【设计模式】JDK实现观察者模式

jdk8和jdk11内置类实现观察者模式

做一个有信仰de人的博客 604

打脸来的太快了,又发现一个Trae的宝藏功能--内置浏览器可以指定机型来显示前端界面

今天给大家分享一个Trae的实用功能,就是SOLO模式下内置浏览器可以指定不同的手机、平板机型来查看前端页面显示效果,我感觉这个功能很棒,忍不住就跟大家分享一下。

cpp加油站的专栏 6567

java jdk 观察者模式_设计模式系列–观察者模式JDK的实现

在JDK中,有哪些是使用了观察者模式呢?我们可以在java.util中可以找到观察者模式,其实javaBeans和Swing中,也都实现了观察者模式。jdk的具体实现大家可以通过下载源码或者使用反编译软件查看,如java.util.Observerable、或者Swing中的JButton。具体实现请自行查看,下面说说java.util.Observerable的不足之处。通过反编译查看java....

weixin_33945512的博客 245

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

转载:JDK中的设计模式(观察者模式)

 在这一部分的内容中,介绍的是一个相对简单但功能强大的模式:Observer模式。希望通过这部分地叙述,大家看了之后,能够对设计模式有一个比较全面地,感性的认识。很多时候,对于一个设计来说(软件上的,建筑上的,或者它他工业上的),经验是至关重要的。好的经验给我们以指导,并节约我们的时间;坏的经验则给我们以借鉴,可以减少失败的风险。然而,从知识层面上来讲,经验只是作为一种工作的积累而存在于个

浮白 1781

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

GoF23-------观察者模式

1. 核心作用 观察者模式主要用于1:N的通知,当一个对象(目标对象Subject或Objservable)的状态变化时,他需要及时通知一系列的对象(观察者对象,Observer),令他们做出响应。 2.通知观察者的方式: *推:每次都把接通知以广播的方式发送给所有观察者,所有观察者只能被动的接受 *拉:观察者只要知道情况即可,至于什么时候获取内容,获取什么...

qq_34170102的博客 184

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

java实现观察者模式

javaapi中提供了两个类,可以帮助实现观察者模式 Observerable为发布者,Observer为订阅者 订阅者:发布者=1:1/1:n/n:m import java.util.Observerable; import java.util.Observer; public class ObserverDemo { public static void main(String[] args...

qq_41738049的博客 256

Java类库Observer——观察者模式

http://www.ibm.com/developerworks/cn/java/l-jdkdp/part1/     软件模式的概念现在比较的广泛,涉及到分析,设计,体系结构,编码,测试,重构等软件构造生命期中的各个部分。这儿主要讨论的是设计模式,指的是在软件设计过程中反复出现的一些问题的解决方法了。不过我们一般在提到设计模式的时候,一般都是指GOF的经典书《Design Patt...

sqcwfiu 220

Java观察者模式 java.util.Observable 与 java.util.Observer 的理解

Part I JDK1.2后,Java提供了对观察者模式的支持接口和实现类。 其中接口 java.util.Observer 用来指定观察者,观察者必须实现 void update(Observable o, Object arg) 方法。 而 java.util.Observable 用来指定观察物(被观察者、可被观察的),并且提供了一系列的方法。读者可以很轻易的使用这个接口和实现类来实现观察者模式。   Part II java.util.Observer 只有一个简单的方法 void up

Kent.Kwan.的技术专栏 1万+

利用Java提供的Observer接口和Observable类实现观察者模式

对于观察者模式,其实Java已经为我们提供了已有的接口和类。对于订阅者(Subscribe,观察者)Java为我们提供了一个接口,JDK源码如下: 1 package java.util; 2 3 public interface Observer { 4 void update(Observable o, Object arg); 5 } 和我们上一篇实现的观察者一...

weixin_33965305的博客 273

【java】Observer和Observable详解

转载请标明出处: 1.必要性 1.1 观察者模式是oo设计中经常用到的模式之一,大家在解决实际需求时,观察者模式往往都会用到,而javase中已经提供了Observer接口和Observable类让你简单快速的实现观察者模式,因此有必要去了解Observer和Observable; 2.观察者模式概述 2.1 角色:被观察对象,观察者2.2 关系: 1).被观察对象:观察者 = 1:n 2).被观察

峰峯的专栏 3万+

观察者模式

很多时候,对于一个设计来说(软件上的,建筑上的,或者它他工业上的),经验是至关重要的。好的经验给我们以指导,并节约我们的时间;坏的经验则给我们以借鉴,可以减少失败的风险。然而,从知识层面上来讲,经验只是作为一种工作的积累而存在于个人的大脑中的,很难被传授或者记录。为了解决这样的问题,人们提出了所谓的模式的概念。所谓模式,是指在一个特定背景下,反复出现的问题解决方案。模式是经验的文档化。  软件模式

renyaning的专栏 327

Java面试知识点(七十五)设计模式之观察者模式

一、初识 1.定义 在对象之间定义了一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象会收到通知并自动更新。 2.参与角色 被观察者(Subject):当需要被观察的状态发生变化时,需要通知队列中所有观察者对象。Subject 需要维持(添加,删除,通知)一个观察者对象的队列列表。 观察者(Observer):接口或抽象类。当 Subject 的状态发生变化时,Observer ...

程序员世杰 1027

【设计模式】观察者模式

最近在看java设计模式,想写点东西做个笔记什么的,于是就想放到blog上。 csdn上讲设计模式的博客有好多了,有的我觉得讲的非常透彻,我初学,如果有什么不对的地方欢迎批评指正,像大神们烤漆啊!   话不多说,下面讲下观察者模式。   说明:这是一种一对多的依赖关系,多个观察者同时监听某一个主题对象,当对象发生改变时,会通知所有的观察者对象(Observer),是他们能够及时更新自己,

RowandJJ 1683

Observer学习笔记

首先还是先来observer模式的uml图 Suject实际是被订阅的消息主题,比如报社,中国移动的天气预报套餐,。。。在Suject中保存了所有订阅者的引用,以便在通知订阅者时使用 Observer就是订阅者了,相当于就是订阅报纸的人了 在JDK中java.util.Observerable实现了Suject的功能,内部是通过线程安全的Vector保存所有订阅者的引用,在发...

dato0123 196

观察者模式的java实现

观察者模式在Java语言中的地位非常重要。在JDK的java.util包中,提供了Observable类以及Observer接口,它们构成了JDK对观察者模式的支持。如图22-5所示: 图22-5 JDK提供的Observable类及Observer接口结构图       (1)  Observer接口       在java.util.Observer接口中只声明一个方

iris0802的专栏 2437
上一篇: 设计模式之观察者模式
下一篇: idea前后跳转箭头
thetimelyrain
博客等级 码龄8年 29粉丝 110原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值