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

server/2025/1/21 5:26:04/

前言

在这里插入图片描述

从今日起,陆续分享《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/server/160089.html

相关文章

网络安全中攻击溯源有哪些方法?

目前网络攻击已经成为常见的安全威胁之一&#xff0c;其造成的危害和损失都是不可估量的&#xff0c;因此网络攻击受到了高度重视。而当我们遭遇网络攻击时&#xff0c;攻击溯源是一项非常重要的工作&#xff0c;可以帮助我们迅速发现并应对各类网络攻击行为&#xff0c;那么网…

【Linux】重定向缓冲区

一、文件内核级缓冲区 在一个struct file内部还要有一个数据结构-----文件的内核级缓冲区。 1.1 write写入操作 当我们去对一个文件写入的时候&#xff0c;那么是如何进行写入的呢&#xff1f; 如&#xff1a;write(3,"hello",..) 先找到文件的内核缓冲区&#…

DDD - 如何设计支持快速交付的DDD技术中台

文章目录 Pre概述打造快速交付团队烟囱式的开发团队(BAD)大前端技术中台(GOOD) 技术中台的特征简单易用的技术中台建设总结 Pre DDD - 软件退化原因及案例分析 DDD - 如何运用 DDD 进行软件设计 DDD - 如何运用 DDD 进行数据库设计 DDD - 服务、实体与值对象的两种设计思路…

Dedecms V110最新版RCE---Tricks

前言 刚发现Dedecms更新了发布版本&#xff0c;顺便测试一下之前的day有没有修复&#xff0c;突然想到了新的tricks去实现RCE。 文章发布的时候估计比较晚了&#xff0c;一直没时间写了。 利用 /uploads/dede/article_string_mix.php /uploads/dede/article_template_rand.…

2025寒假备战蓝桥杯01---朴素二分查找的学习

文章目录 1.暴力方法的引入2.暴力解法的思考 与改进3.朴素二分查找的引入4.朴素二分查找的流程5.朴素二分查找的细节6.朴素二分查找的题目 1.暴力方法的引入 对于下面的这个有序的数据元素的组合&#xff0c;我们的暴力解法就是挨个进行遍历操作&#xff0c;一直找到和我们的这…

Wi-Fi 7、Wi-Fi 6 与 5G、4G 的全方位对比

随着无线通信技术的飞速发展&#xff0c;Wi-Fi 7、Wi-Fi 6&#xff0c;以及5G、4G 已经成为人们生活和工作中不可或缺的网络技术。无论是家庭网络、高速移动通信&#xff0c;还是工业物联网&#xff0c;这些技术都在发挥各自的作用。那么&#xff0c;它们之间有什么区别&#x…

wireshark抓路由器上的包 抓包路由器数据

文字目录 抓包流程概述设置抓包配置选项 设置信道设置无线数据包加密信息设置MAC地址过滤器 抓取联网过程 抓包流程概述 使用Omnipeek软件分析网络数据包的流程大概可以分为以下几个步骤&#xff1a; 扫描路由器信息&#xff0c;确定抓包信道&#xff1b;设置连接路由器的…

Android 高版本如何获取App安装列表?

有个需求需要获取App内的安装列表,但是现在在高版本Android中,只能获取到一部分App效果,我获取的代码如下: val calendar Calendar.getInstance()val packageManager context.packageManagerval usageStatsManager context.getSystemService(Context.USAGE_STATS_SERVICE) …