【HeadFirst系列之HeadFirst设计模式】第3天之观察者模式

ops/2025/1/21 1:09:53/

前言

在这里插入图片描述

从今日起,陆续分享《HeadFirst设计模式》的读书笔记,希望能够帮助大家更好的理解设计模式,提高自己的编程能力。

设计模式本质上就是前人比较成熟的经验和智慧。他们遇到过相同的问题,也顺利地解决了这些问题。

跟随前人的脚步,可以少走弯路,也可以站在巨人的肩膀上看得更远。

使用模式最好的方式是:"把模式装进脑子里,然后在你的设计和已有的应用中,寻找何处可以使用它们。"以往是代码复用,现在是经验复用。

今天要分享的是【设计模式入门之观察者模式】,希望对大家有所帮助。

书籍精彩内容

气象观测站

在这里插入图片描述

这个图片有点像我们平时接到新需求的BRD,然后产品经理会把它转换为PRD,最后我们开发人员根据PRD进行开发。

需求描述:

1.新建应用

2.获取气象站数据并在应用展示

3.应用可以实时获取气象站数据并更新,同时展示

4.应用具有扩展性,可以添加更多的展示方式

。。。

在这里插入图片描述

WeatherData对象从气象站取得数据(温度、湿度、气压),在显示装置展示。

气象数据类

在这里插入图片描述

WeatherData类有如下方法:

getTemperature():获取温度

getHumidity():获取湿度

getPressure():获取气压

measurementsChanged():当气象站测量数据更新时,调用此方法

。。。
我们的代码主要在measurementsChanged()方法中编写。

在这里插入图片描述

WeatherData对象有3个方法,分别获取温度、湿度、气压

WeatherData对象有一个measurementsChanged()方法,当气象站测量数据更新时,调用此方法

有三种显示装置:目前天气状况、天气统计、天气预报

未来可能会有第4,第5种,甚至更多种显示装置

第一次尝试气象站

在这里插入图片描述

针对实现编程,而不是接口编程,耦合性太高。

在这里插入图片描述

改变的地方需要封装起来

不要针对实现编程

认识观察者模式

在这里插入图片描述

报纸的订阅涉及三个对象:报社、订阅者、报纸

订阅者订阅报纸,报社发布新报纸,订阅者收到新报纸

订阅者取消订阅,报社不再发送新报纸

在这里插入图片描述

主题(Subject):出版者

观察者(Observer):订阅者

观察者模式的一天

在这里插入图片描述
在这里插入图片描述

鸭子申请成为观察者

老鼠申请从观察者列表移除

五分钟短剧

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

后泡沫时期的两名软件工程师通过猎头找工作

猎头把求职者加入求职者清单,一有消息就通知求职者

这里猎头是主题,求职者是观察者

定义观察者模式

在这里插入图片描述
在这里插入图片描述

观察者模式定义了对象之间的一对多依赖,

这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

松耦合

在这里插入图片描述

其实dubbo就是一个松耦合的例子,面向接口编程,调用方不用关注实现方实现细节。

规划气象站

在这里插入图片描述

设计气象站

在这里插入图片描述

实现气象站

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

测试气象站

在这里插入图片描述
在这里插入图片描述

围炉夜话:主题与观察者

在这里插入图片描述
在这里插入图片描述

Java内置的观察者模式

在这里插入图片描述
在这里插入图片描述

幕后花絮

在这里插入图片描述

重做目前状况布告板

在这里插入图片描述
在这里插入图片描述

测试驱动

在这里插入图片描述
在这里插入图片描述

观察者与Swing

在这里插入图片描述
在这里插入图片描述

你的设计工具箱

在这里插入图片描述

代码实现

观察者设计模式源码地址

第一版(自己实现)

  • 主题
java">public interface Subject {void registerObserver(Observer o);void removeObserver(Observer o);void notifyObservers();
}
java">public class WeatherData implements Subject {private ArrayList observers;private float temperature;private float humidity;private float pressure;public WeatherData() {observers = new ArrayList();}@Overridepublic void registerObserver(Observer o) {observers.add(o);}@Overridepublic void removeObserver(Observer o) {int i = observers.indexOf(o);if (i > 0) {observers.remove(i);}}@Overridepublic void notifyObservers() {for (int i = 0; i < observers.size(); i++) {Observer observer = (Observer) observers.get(i);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();}
}
  • 观察者
java">public interface Observer {void update(float temp, float humidity, float pressure);
}
java">public interface DisplayElement {void display();
}
java">public class CurrentConditionsDisplay implements Observer, DisplayElement {private float temperature;private float humidity;private Subject weatherData;public CurrentConditionsDisplay(Subject weatherData) {this.weatherData = weatherData;weatherData.registerObserver(this);}@Overridepublic void display() {System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");}@Overridepublic void update(float temperature, float humidity, float pressure) {this.temperature = temperature;this.humidity = humidity;display();}
}
java">public class StatisticsDisplay implements Observer, DisplayElement {private float temperature;private float humidity;private Subject weatherData;public StatisticsDisplay(Subject weatherData) {this.weatherData = weatherData;weatherData.registerObserver(this);}@Overridepublic void display() {System.out.println("天气统计展示实现");}@Overridepublic void update(float temperature, float humidity, float pressure) {this.temperature = temperature;this.humidity = humidity;display();}
}
java">public class ForecastDisplay implements Observer, DisplayElement {private float temperature;private float humidity;private Subject weatherData;public ForecastDisplay(Subject weatherData) {this.weatherData = weatherData;weatherData.registerObserver(this);}@Overridepublic void display() {System.out.println("天气预报展示实现");}@Overridepublic void update(float temperature, float humidity, float pressure) {this.temperature = temperature;this.humidity = humidity;display();}
}
java">public class HeatIndexDisplay implements Observer, DisplayElement {private float temperature;private float humidity;private Subject weatherData;public HeatIndexDisplay(Subject weatherData) {this.weatherData = weatherData;weatherData.registerObserver(this);}@Overridepublic void display() {System.out.println("酷热指数展示实现");}@Overridepublic void update(float temperature, float humidity, float pressure) {this.temperature = temperature;this.humidity = humidity;display();}
}
  • 测试
java">public class WeatherStation {public static void main(String[] args) {WeatherData weatherData = new WeatherData();CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);HeatIndexDisplay heatIndexDisplay = new HeatIndexDisplay(weatherData);weatherData.setMeasurements(80, 65, 30.4f);System.out.println();weatherData.setMeasurements(82, 70, 29.2f);System.out.println();weatherData.setMeasurements(78, 90, 29.2f);System.out.println();}
}

运行结果:

Current conditions: 80.0F degrees and 65.0% humidity
天气统计展示实现
天气预报展示实现
酷热指数展示实现Current conditions: 82.0F degrees and 70.0% humidity
天气统计展示实现
天气预报展示实现
酷热指数展示实现Current conditions: 78.0F degrees and 90.0% humidity
天气统计展示实现
天气预报展示实现
酷热指数展示实现

javautil_343">第二版(用JDK自带的实现,实现了Observable和Observer接口,都位于java.util包下)

  • 主题,实现了java.util.Observable接口
java">public class WeatherDataV2 extends Observable {private float temperature;private float humidity;private float pressure;public WeatherDataV2() {}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;}
}
  • 观察者,实现了java.util.Observer接口
java">public class CurrentConditionsDisplayV2 implements Observer, DisplayElement {Observable observable;private float temperature;private float humidity;public CurrentConditionsDisplayV2(Observable observable) {this.observable = observable;observable.addObserver(this);}@Overridepublic void display() {System.out.println("Current conditions:" + temperature+ "F degrees and " + humidity + "% humidity");}@Overridepublic void update(Observable o, Object arg) {if (o instanceof WeatherDataV2) {WeatherDataV2 weatherDataV2 = (WeatherDataV2) o;this.temperature = weatherDataV2.getTemperature();this.humidity = weatherDataV2.getHumidity();display();}}
}
java">public class StatisticsDisplayV2 implements Observer, DisplayElement {Observable observable;private float temperature;private float humidity;public StatisticsDisplayV2(Observable observable) {this.observable = observable;observable.addObserver(this);}@Overridepublic void display() {System.out.println("天气统计展示实现V2");}@Overridepublic void update(Observable o, Object arg) {if (o instanceof WeatherDataV2) {WeatherDataV2 weatherDataV2 = (WeatherDataV2) o;this.temperature = weatherDataV2.getTemperature();this.humidity = weatherDataV2.getHumidity();display();}}
}
java">public class ForecastDisplayV2 implements Observer, DisplayElement {Observable observable;private float temperature;private float humidity;public ForecastDisplayV2(Observable observable) {this.observable = observable;observable.addObserver(this);}@Overridepublic void display() {System.out.println("天气预报展示实现V2");}@Overridepublic void update(Observable o, Object arg) {if (o instanceof WeatherDataV2) {WeatherDataV2 weatherDataV2 = (WeatherDataV2) o;this.temperature = weatherDataV2.getTemperature();this.humidity = weatherDataV2.getHumidity();display();}}
}
java">public class HeatIndexDisplayV2 implements Observer, DisplayElement {Observable observable;private float temperature;private float humidity;public HeatIndexDisplayV2(Observable observable) {this.observable = observable;observable.addObserver(this);}@Overridepublic void display() {System.out.println("酷热指数展示实现V2");}@Overridepublic void update(Observable o, Object arg) {if (o instanceof WeatherDataV2) {WeatherDataV2 weatherDataV2 = (WeatherDataV2) o;this.temperature = weatherDataV2.getTemperature();this.humidity = weatherDataV2.getHumidity();display();}}
}
  • 测试(结果并不是按照预期顺序打印)
java">public class WeatherStationV2 {public static void main(String[] args) {WeatherDataV2 weatherDataV2 = new WeatherDataV2();CurrentConditionsDisplayV2 currentDisplayV2 = new CurrentConditionsDisplayV2(weatherDataV2);StatisticsDisplayV2 statisticsDisplayV2 = new StatisticsDisplayV2(weatherDataV2);ForecastDisplayV2 forecastDisplayV2 = new ForecastDisplayV2(weatherDataV2);HeatIndexDisplayV2 heatIndexDisplayV2 = new HeatIndexDisplayV2(weatherDataV2);weatherDataV2.setMeasurements(80, 65, 30.4f);System.out.println();weatherDataV2.setMeasurements(82, 70, 29.2f);System.out.println();weatherDataV2.setMeasurements(78, 90, 29.2f);System.out.println();}
}

运行结果:

酷热指数展示实现V2
天气预报展示实现V2
天气统计展示实现V2
Current conditions:80.0F degrees and 65.0% humidity酷热指数展示实现V2
天气预报展示实现V2
天气统计展示实现V2
Current conditions:82.0F degrees and 70.0% humidity酷热指数展示实现V2
天气预报展示实现V2
天气统计展示实现V2
Current conditions:78.0F degrees and 90.0% humidity

Java wing demo

java">public class SwingObserverExample {JFrame frame;public static void main(String[] args) {SwingObserverExample example = new SwingObserverExample();example.go();}public void go() {frame = new JFrame();JButton button = new JButton("Should I do it?");button.addActionListener(new AngelListener());button.addActionListener(new AngelListener());frame.getContentPane().add(BorderLayout.CENTER, button);}class AngelListener implements ActionListener {public void actionPerformed(ActionEvent event) {System.out.println("Don't do it, you might regret it!");}}class DevilListener implements ActionListener {@Overridepublic void actionPerformed(ActionEvent e) {System.out.println("Come on,do it!");}}
}
  • 运行结果
控制台输出如下结果:
2025-01-19 13:31:40.726 java[80134:9279486] +[IMKClient subclass]: chose IMKClient_Modern
2025-01-19 13:31:40.726 java[80134:9279486] +[IMKInputSession subclass]: chose IMKInputSession_Modern图形化页面还未点击,就消失了

实际运用场景

  • 生活场景

    1.家里的摄像头监控,有异常就手机通知我

    2.订阅了某个公众号,有新文章就通知我

    3.抢火车票,有票就通知我

    4.电商购物,订阅到货提醒,订阅秒杀提醒等

    5.。。。
  • 代码场景

    1.mq消息队列

    2.jdk自带(Oberver,Swing)

    3.。。。

套公式

新需求是什么,是否有需要实时监听的场景

如果有确认主题(被监听者),确认观察者(监听者),

那么就可以套用观察者模式

有趣的事

1.家里冰箱贴改为:代码贴主题,既可以当冰箱贴,又可以玩类似消消乐类似游戏

总结

1.设计原则:

  • 找出程序中会变化的方面,然后将其和固定不变的方面相分离。【封装变化】
  • 针对接口编程,不针对实现编程
  • 多用组合,少用继承

2.观察者模式

  • 定义
    观察者模式–在对象之间定义一对多的依赖,这样一来,省一个对象改 变状态,依赖它的对象都会收到通知, 并自动更新。
  • MVC模式
    一个新的模式,以松耦合方式在一系列对象之间沟通状态。我们目前还没看到观察者模式的代表人物–MVC,以后就会看到了。

3.类图:

4.this关键字:

5.内部类:


http://www.ppmy.cn/ops/151799.html

相关文章

“深入浅出”系列之数通篇:(5)TCP的三次握手和四次挥手

TCP&#xff08;传输控制协议&#xff09;的三次握手和四次挥手是TCP连接建立和释放的过程。 一、TCP三次握手 TCP三次握手是为了建立可靠的连接&#xff0c;确保客户端和服务器之间的通信能力。具体过程如下&#xff1a; 第一次握手&#xff1a;客户端向服务器发送一个带有…

Spring Boot使用WebSocket

跟其他http的控制层类似&#xff0c;我们需要实现一个基本的 WebSocket 服务器端点。 PlatformAsyncWebSocket.java package com.rmeservice.platform.websocket;import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component;import javax.websocket…

实战经验:使用 Python 的 PyPDF 进行 PDF 操作

文章目录 1. 为什么选择 PyPDF&#xff1f;2. 安装 PyPDF3. PDF 文件的合并与拆分3.1 合并 PDF 文件3.2 拆分 PDF 文件 4. 提取 PDF 文本5. 修改 PDF 元信息6. PDF 加密与解密6.1 加密 PDF6.2 解密 PDF 7. 页面旋转与裁剪7.1 旋转页面7.2 裁剪页面 8. 实战经验总结 PDF 是一种非…

使用libwebsocket技术总结

一、编译libwebsocket 1) 需要使用Cmake工具&#xff0c;将根目录下CMakeLists.txt打开后&#xff0c;需要配置openssl库的路径 2) 当前libwebsocket v3.2版本需要使用openssl v1.1.x以上版本&#xff0c;否则ssl安全协议支持只能选择内置ssl模块&#xff0c;一般都选择opens…

08、如何预防SQL注入

目录 1、分析及其存在哪些危险 2、预防SQL注入 1、分析及其存在哪些危险 原理: SQL 注入是一种常见的网络攻击手段,攻击者通过在用户输入中插入恶意的 SQL 语句,利用程序对用户输入处理不当的漏洞,使恶意 SQL 语句被数据库服务器执行。 通常发生在应用程序将用户输入直接拼…

Web安全|渗透测试|网络安全

基础入门(P1-P5) p1概念名词 1.1域名 什么是域名&#xff1f; 域名&#xff1a;是由一串用点分隔的名字组成的Internet上某一台计算机或计算机组的名称&#xff0c;用于在数据传输时对计算机的定位标识&#xff08;有时也指地理位置&#xff09;。 什么是二级域名多级域名…

【python_钉钉群发图片】

需求&#xff1a; **在钉钉群发图片&#xff0c;需要以图片的形式展示&#xff0c;如图所示&#xff1a;**但是目前影刀里面没有符合条件的指令 解决方法&#xff1a; 1、在钉钉开发者后台新建一个自建应用&#xff0c;发版&#xff0c;然后获取里面的appkey和appsecret&am…

【设计模式】 单例模式(单例模式哪几种实现,如何保证线程安全,反射破坏单例模式)

单例模式 作用&#xff1a;单例模式的核心是保证一个类只有一个实例&#xff0c;并且提供一个访问实例的全局访问点。 实现方式优缺点饿汉式线程安全&#xff0c;调用效率高 &#xff0c;但是不能延迟加载懒汉式线程安全&#xff0c;调用效率不高&#xff0c;能延迟加载双重检…