• 尚硅谷设计模式学习(十八)观察者模式


    天气预报项目引入观察者模式

    • 气象站可以将每天测量到的温度,湿度,气压等等以公告的形式发布给第三方。
    • 需要设计开放型 API,便于其他第三方也能接入气象站获取数据。
    • 测量数据更新时,要能实时的通知给第三方

    传统方案

    两个第三方网站

    1. public class Website1 {
    2. //温度
    3. private float temperature;
    4. //湿度
    5. private float humidity;
    6. //气压
    7. private float pressure;
    8. //修改气象数据
    9. public void update(float temperature, float humidity, float pressure){
    10. this.temperature = temperature;
    11. this.humidity = humidity;
    12. this.pressure = pressure;
    13. display();
    14. }
    15. //显示气象数据
    16. public void display(){
    17. System.out.println("----网站1气象数据服务----");
    18. System.out.println("温度:" + temperature);
    19. System.out.println("湿度:" + humidity);
    20. System.out.println("气压:" + pressure);
    21. }
    22. }
    1. public class Website2 {
    2. //温度
    3. public float temperature;
    4. //湿度
    5. public float humidity;
    6. //气压
    7. public float pressure;
    8. //修改气象数据
    9. public void update(float temperature, float humidity, float pressure){
    10. this.temperature = temperature;
    11. this.humidity = humidity;
    12. this.pressure = pressure;
    13. display();
    14. }
    15. //显示气象数据
    16. public void display(){
    17. System.out.println("----网站2气象数据服务----");
    18. System.out.println("温度:" + temperature);
    19. System.out.println("湿度:" + humidity);
    20. System.out.println("气压:" + pressure);
    21. }
    22. }

    气象数据类,包含最新的天气情况信息,当数据有更新时,就主动的调用setData方法,这样第三方网站就能看到最新消息。

    1. public class WeatherData {
    2. //温度;
    3. private float temperature;
    4. //湿度;
    5. private float humidity;
    6. //气压;
    7. private float pressure;
    8. // 聚合第三方网站,方便通知最小消息
    9. private Website1 website1;
    10. private Website2 website2;
    11. public void setWebsite1(Website1 website1) {
    12. this.website1 = website1;
    13. }
    14. public void setWebsite2(Website2 website2) {
    15. this.website2 = website2;
    16. }
    17. //修改气象数据
    18. public void setData(float temperature, float humidity, float pressure){
    19. this.temperature = temperature;
    20. this.humidity = humidity;
    21. this.pressure = pressure;
    22. website1.update(temperature,humidity,pressure);
    23. website2.update(temperature,humidity,pressure);
    24. }
    25. }

    测试

    1. public class Clint {
    2. public static void main(String[] args) {
    3. WeatherData weatherData = new WeatherData();
    4. Website1 website1 = new Website1();
    5. Website2 website2 = new Website2();
    6. weatherData.setWebsite1(website1);
    7. weatherData.setWebsite2(website2);
    8. //设置气象数据
    9. weatherData.setData(50.0f,50.0f,50.0f);
    10. //修改气象数据
    11. System.out.println("----气象台修改气象数据----");
    12. weatherData.setData(10.0f,10.0f,10.0f);
    13. }
    14. }

    结果

    ----网站1气象数据服务----
    温度:50.0
    湿度:50.0
    气压:50.0
    ----网站2气象数据服务----
    温度:50.0
    湿度:50.0
    气压:50.0
    ----气象台修改气象数据----
    ----网站1气象数据服务----
    温度:10.0
    湿度:10.0
    气压:10.0
    ----网站2气象数据服务----
    温度:10.0
    湿度:10.0
    气压:10.0

    问题分析 

    无法在运行时动态的添加第三方。

    当增加一个第三方,需要修改气象数据类的方法,不利于维护。

    一、观察者模式

    1、基本介绍

    观察者模式:对象之间多对一依赖的一种设计方案,被依赖的对象为 Subject,依赖的对象为 Observer,Subject 通知  Observer 变化,比如这里的气象数据是  Subject, 网站是Observer。

    • Subject:登记注册、移除和通知
    • Observer:接收输入 

    2、代码实现

    观察者接口:管理不同的用户

    1. // 观察者接口 --> 管理不同的用户
    2. public interface Observer {
    3. //更新天气数据;(温度,气压,湿度)
    4. public void update(float temperature, float humidity,float pressure);
    5. }

    两个第三方网站

    1. public class Website1 implements Observer{
    2. //温度;
    3. private float temperature;
    4. //湿度;
    5. private float humidity;
    6. //气压;
    7. private float pressure;
    8. //更新气象数据;
    9. public void update(float temperature,float humidity,float pressure) {
    10. this.temperature = temperature;
    11. this.humidity = humidity;
    12. this.pressure = pressure;
    13. display();
    14. }
    15. //显示气象数据
    16. public void display(){
    17. System.out.println("----网站1气象数据服务----");
    18. System.out.println("温度:" + temperature);
    19. System.out.println("湿度:" + humidity);
    20. System.out.println("气压:" + pressure);
    21. }
    22. }
    1. public class Website2 implements Observer{
    2. //温度;
    3. private float temperature;
    4. //湿度;
    5. private float humidity;
    6. //气压;
    7. private float pressure;
    8. //更新气象数据;
    9. public void update(float temperature,float humidity,float pressure) {
    10. this.temperature = temperature;
    11. this.humidity = humidity;
    12. this.pressure = pressure;
    13. display();
    14. }
    15. //显示气象数据
    16. public void display(){
    17. System.out.println("----网站2气象数据服务----");
    18. System.out.println("温度:" + temperature);
    19. System.out.println("湿度:" + humidity);
    20. System.out.println("气压:" + pressure);
    21. }
    22. }

    定义平台的管理接口

    1. public interface Subject {
    2. //注册,增加;
    3. public void registerObserver(Observer observer);
    4. //移出;
    5. public void remove(Observer observer);
    6. //通知所有的注册的用户
    7. public void notifyObserver();
    8. }

     气象数据类

    1. public class WeatherData implements Subject{
    2. //温度;
    3. private float temperatrue;
    4. //湿度;
    5. private float humidity;
    6. //气压;
    7. private float pressure;
    8. //观察者(用户集合)
    9. private ArrayList observerArrayList;
    10. //初始化信息;
    11. public WeatherData() {
    12. observerArrayList = new ArrayList();
    13. }
    14. //设置传入数据;
    15. public void setData(float temperature, float humidity, float pressure) {
    16. this.temperatrue = temperature;
    17. this.humidity = humidity;
    18. this.pressure = pressure;
    19. notifyObserver();
    20. }
    21. public void registerObserver(Observer observer) {
    22. observerArrayList.add(observer);
    23. }
    24. public void remove(Observer observer) {
    25. //若存在就移除;
    26. if(observerArrayList.contains(observer)){
    27. observerArrayList.remove(observer);
    28. }
    29. }
    30. public void notifyObserver() {
    31. for (int i = 0; i < observerArrayList.size(); i++) {
    32. observerArrayList.get(i).update(this.humidity, this.temperatrue, this.pressure);
    33. }
    34. }
    35. }

     测试

    1. public class CLient {
    2. public static void main(String[] args) {
    3. WeatherData weatherData = new WeatherData();
    4. Website1 website1 = new Website1();
    5. Website2 website2 = new Website2();
    6. //添加发布的平台;
    7. weatherData.registerObserver(website1);
    8. weatherData.registerObserver(website2);
    9. //设置气象数据;
    10. weatherData.setData(31f,60f,180f);
    11. //修改气象数据
    12. weatherData.setData(20f,40f,60f);
    13. }
    14. }

    结果 

    ----网站1气象数据服务----
    温度:31.0
    湿度:60.0
    气压:180.0
    ----网站2气象数据服务----
    温度:31.0
    湿度:60.0
    气压:180.0
    ----网站1气象数据服务----
    温度:20.0
    湿度:40.0
    气压:60.0
    ----网站2气象数据服务----
    温度:20.0
    湿度:40.0
    气压:60.0

    3、观察者模式的好处

    1)观察者模式设计后,会以集合的方式来管理用户(Observer),包括注册,移除和通知

    2)这样,我们增加观察者(这里可以理解成一个新的公告板),就不需要去修改核心类WeatherData,遵守了  ocp  原则。

    二、观察者模式在 Jdk 应用的源码分析

    Jdk  的 Observable  类就使用了观察者模式

    1. public class Observable {
    2. private boolean changed = false;
    3. private Vector obs;
    4. public Observable() {
    5. obs = new Vector<>();
    6. }
    7. public synchronized void addObserver(Observer o) {
    8. if (o == null)
    9. throw new NullPointerException();
    10. if (!obs.contains(o)) {
    11. obs.addElement(o);
    12. }
    13. }
    14. public synchronized void deleteObserver(Observer o) {
    15. obs.removeElement(o);
    16. }
    17. public void notifyObservers() {
    18. notifyObservers(null);
    19. }
    20. public void notifyObservers(Object arg) {
    21. Object[] arrLocal;
    22. synchronized (this) {
    23. if (!changed)
    24. return;
    25. arrLocal = obs.toArray();
    26. clearChanged();
    27. }
    28. for (int i = arrLocal.length-1; i>=0; i--)
    29. ((Observer)arrLocal[i]).update(this, arg);
    30. }
    31. public synchronized void deleteObservers() {
    32. obs.removeAllElements();
    33. }
    34. protected synchronized void setChanged() {
    35. changed = true;
    36. }
    37. protected synchronized void clearChanged() {
    38. changed = false;
    39. }
    40. public synchronized boolean hasChanged() {
    41. return changed;
    42. }
    43. public synchronized int countObservers() {
    44. return obs.size();
    45. }
    46. }
    1. public interface Observer {
    2. void update(Observable o, Object arg);
    3. }
    • Observable的作用等价于前面的Subject
    • Observable 是类,不是接口,类中已经实现了核心的方法,即管理 Observer 的方法
    • Observer 的作用等价于前面的Observer,有  update方法
    • Observable 和 Observer 的使用方法和前面讲过的一样,只是 Observable 是类,通过继承来实现观察者模式。
  • 相关阅读:
    摄像头V4L2获取的YUY2格式转YUV420格式
    Informatica使用操作流程--聚合、表达式转换、查找、排序组件的使用 案例3
    第Y8周:yolov8.yaml文件解读
    一些面试总结123
    重新认识下JVM级别的本地缓存框架Guava Cache——优秀从何而来
    TiUP FAQ
    SHT31/85温湿度传感器驱动代码(基于GD32F103)
    【C语言】break 关键字
    【环境搭建】linux docker-compose安装seata1.6.1,使用nacos注册、db模式
    基于R语言的贝叶斯网络模型、现代贝叶斯统计学方法
  • 原文地址:https://blog.csdn.net/qq_51409098/article/details/126940415