观察者设计模式知多少

news/2024/7/9 1:47:04

目录

目标

概述

实现 

推设计模式

拉设计模式

被动观察者设计模式


目标

熟悉观察者设计模式,了解观察者设计模式的使用场景、具体实现(包括:推设计模式、拉设计模式、被动观察者设计模式)


概述

一、行为设计模式

行为设计模式是设计模式的一种类型。该类型的设计模式关注的重点在于对象的行为(通信和交互),而非对象的创建方式。较为常见的行为设计模式有:观察者模式、策略模式、命令模式、责任链模式等。优点是减少了对象之间的耦合度

二、观察者设计模式

对象之间存在一对多的依赖关系,多个观察者对象同时监听某一个主题对象(被观察者对象)。当主题对象的状态发生改变时会通知其他观察者对象。主题对象实现思路:

  1. 主题对象类定义一个集合observerList用来保存多个观察者对象。
  2. 定义观察者对象注册到主题对象的方法、主题对象从注册表中剔除指定观察者对象的方法、定义通知方法。
  3. 当对象状态发生改变时调用该方法,以遍历observerList的方式通知所有观察者对象。

优点

  1. 被观察者使用注册表的方式囊括了所有观察者,降低了观察者对象和被观察者对象之间的依赖关系,提高了系统的扩展性和可维护性。
  2. 被观察者类提供了注册,剔除的方法,使得代码扩展性增强。
  3. 该模式实现了事件驱动的方式,使业务实现方案变得更灵活。

缺点

  1. 观察者过多会导致内存开销大。
  2. 容易发生循环依赖问题。

种类

  • 推设计模式:最简单的模式,指被观察者主动将状态推送给观察者。
  • 拉设计模式:被观察者只告知观察者状态发生了改变,观察者需要通过主动去“拉”的方式,获取被观察者的具体状态。
  • 被动观察者设计模式:引入了一个中介者对象来协调主题对象和观察者之间的交互。主题对象不再直接通知观察者,而是将状态变化通知给中介者对象,由中介者对象负责通知观察者。

三、使用场景

  • 一个对象发生改变需要通知其他对象,其他对象可以自由选择监听或者不监听。
  • 一个对象发生改变需要通知其他对象,其他对象的类型和数量不确定时。

四、列举观察者模式在成熟的框架中的应用

  • 在RabbitMQ中,Exchange和Queue之间的绑定关系。
  • Java AWT/Swing事件处理机制。
  • Spring Framework事件机制。
  • Java Message Service(JMS)。

实现 

推设计模式

需求

多个用户订阅了天气预报系统,则天气预报作为被观察者对象,一旦天气预报发生更新,则订阅者需要马上感知并获取天气预报状态。

观察者接口

package com.ctx.observer.push;

// 定义用户作为观察者对象
interface Observer {
    public void update(String weather);
}

观察者接口实现类

package com.ctx.observer.push;

// 实现具体的观察者对象
class User implements Observer {
    private String name;

    public User(String name) {
        this.name = name;
    }

    // 接收天气预报信息
    public void update(String weather) {
        System.out.println(name + "收到天气预报信息:" + weather);
    }
}

被观察者类

package com.ctx.observer.push;

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

// 定义天气预报机构作为主题对象
class WeatherForecast {
    private List<Observer> observers = new ArrayList<Observer>();
    private String weather;

    // 注册观察者对象
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    // 移除观察者对象
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    // 通知所有观察者对象
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(weather);
        }
    }

    // 更新天气预报信息
    public void setWeather(String weather) {
        this.weather = weather;
        notifyObservers();
    }
}

调用测试类

package com.ctx.observer.push;

// 测试代码
public class Test {
    public static void main(String[] args) {
        WeatherForecast weatherForecast = new WeatherForecast();

        // 创建多个用户作为观察者对象
        User user1 = new User("张三");
        User user2 = new User("李四");
        User user3 = new User("王五");

        // 注册观察者对象
        weatherForecast.registerObserver(user1);
        weatherForecast.registerObserver(user2);
        weatherForecast.registerObserver(user3);

        // 发布天气预报信息
        weatherForecast.setWeather("今天晴朗,温度26℃");

        // 移除观察者对象
        weatherForecast.removeObserver(user2);

        // 发布天气预报信息
        weatherForecast.setWeather("明天有雨,温度22℃");
    }
}

拉设计模式

需求

多个用户订阅了新闻频道,则新闻频道作为被观察者对象,一旦新闻频道发生更新,则订阅者需要马上感知新闻频道发生了更新。但是具体更新了什么新闻,需要由用户主动去获取。

观察者接口

package com.ctx.observer.pull;

// 定义观察者对象
interface Observer {
    void update(News news);
}

观察者接口实现类

package com.ctx.observer.pull;

// 定义具体的观察者对象(居民对象)
class Resident implements Observer {
    private String name;

    public Resident(String name) {
        this.name = name;
    }

    // 拉模式:观察者主动获取消息内容
    public void update(News news) {
        System.out.println(name + "收到消息: " + news.getNewsContent());
    }

    public String getName() {
        return name;
    }
}

被观察者类

package com.ctx.observer.pull;

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

// 定义被观察者对象(新闻对象是被观察者)
class News {
    private List<Observer> observers = new ArrayList<>();
    private String newsContent;

    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    public void setNewsContent(String newsContent) {
        this.newsContent = newsContent;
        notifyObservers();
    }

    // 通知观察者更新消息
    private void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(this);
        }
    }

    // 获取消息内容
    public String getNewsContent() {
        return newsContent;
    }
}

调用测试类

package com.ctx.observer.pull;

public class Test {
    public static void main(String[] args) {
        News news = new News();

        // 居民订阅新闻
        Resident resident1 = new Resident("张三");
        Resident resident2 = new Resident("李四");
        news.addObserver(resident1);
        news.addObserver(resident2);

        // 设置新闻内容,观察者拉取消息内容
        news.setNewsContent("今天是个好日子!");
    }
}

被动观察者设计模式

需求

患者住院治疗,则患者作为被观察者,医生和护士作为观察者。但是医生和护士不能一直陪在患者身边,为了及时响应,医院安装了医疗监护系统,一旦患者有需要则通过医疗监护系统通知医生和护士,医疗监护系统起到了中介者的作用,它来协调观察者和被观察者之间的交互。

观察者接口

package com.ctx.observer.passive;

// 定义观察者接口
interface Observer {
    void update(); // 更新观察者状态
}

观察者接口实现类

package com.ctx.observer.passive;

// 定义具体的观察者,即医生和护士类
class MedicalStaff implements Observer {
    private String name;
    private Subject patient;

    public MedicalStaff(String name, Subject patient) {
        this.name = name;
        this.patient = patient;
        patient.registerObserver(this); // 注册观察者
    }

    @Override
    public void update() {
        String condition = ((Patient) patient).getCondition(); // 获取被观察者状态
        System.out.println(name + "收到病人病情更新通知,病情为:" + condition); // 处理病情变化
    }
}

中介者

package com.ctx.observer.passive;

// 定义中介者,即医疗监护系统类
class MedicalMonitor {
    private Subject patient;

    public MedicalMonitor(Subject patient) {
        this.patient = patient;
    }

    public void setPatientCondition(String condition) {
        ((Patient) patient).setCondition(condition); // 更新被观察者状态
    }
}

被观察者接口

package com.ctx.observer.passive;

// 定义被观察者接口
interface Subject {
    void registerObserver(Observer observer); // 注册观察者
    void removeObserver(Observer observer); // 移除观察者
    void notifyObservers(); // 通知观察者
}

被观察者接口实现类

package com.ctx.observer.passive;

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

// 定义具体的被观察者,即病人类
class Patient implements Subject {
    private List<Observer> observers; // 观察者列表
    private String condition; // 病情

    public Patient() {
        observers = new ArrayList<>();
    }

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(); // 通知每个观察者更新状态
        }
    }

    public void setCondition(String condition) {
        this.condition = condition;
        notifyObservers(); // 状态变化后通知所有观察者更新状态
    }

    public String getCondition() {
        return condition;
    }
}

调用测试类

package com.ctx.observer.passive;

// 测试
public class Test {
    public static void main(String[] args) {
        Patient patient = new Patient(); // 创建被观察者
        MedicalMonitor monitor = new MedicalMonitor(patient); // 创建中介者
        MedicalStaff doctor = new MedicalStaff("张医生", patient); // 创建观察者
        MedicalStaff nurse = new MedicalStaff("李护士", patient); // 创建观察者

        monitor.setPatientCondition("发热"); // 病人状态变化,触发通知

        patient.removeObserver(doctor); // 病人移除一个观
        System.out.println("--------------------------");
        monitor.setPatientCondition("感冒"); // 病人状态变化,触发通知
    }
}

http://lihuaxi.xjx100.cn/news/1070953.html

相关文章

浅谈个人对“孔乙己的长衫“的感受

名人说&#xff1a;往者不可谏&#xff0c;来者犹可追。——《论语微子篇》 创作者&#xff1a;Code_流苏(CSDN) ★温馨提示&#xff1a;以下仅代表个人观点&#xff0c;不代表其它任何人看法。 目录 〇、缘由一、社会对于学历和职业之间的关系认知是怎样的&#xff1f;二、学…

刚刚学习Java的

作为一个刚刚学习Java的人&#xff0c;以下是您可以 学习基本的编程概念和语法&#xff1a; 在学习Java之前&#xff0c;您需要了解一些基本的编程概念和语法&#xff0c;例如变量、数据类型、运算符、控制流等等。您可以通过以下几种方式来学习这些基础知识&#xff1a; 在…

ubuntu中编译serialplot

源码链接&#xff1a;GitHub - hyOzd/serialplot: Small and simple software for plotting data from serial port in realtime. 安装依赖 apt install qtbase5-dev libqt5serialport5-dev cmake mercurial qttools5-dev libqt5svg5-dev 下载编译serialplot hg clone https…

学习笔记——初识SVG

学习前端可视化&#xff0c;学习使用SVG&#xff0c;让页面内容更加丰富 一、基本概念 位图&#xff1a;放大会失真图像边缘有锯齿&#xff1b;是由像素点组成&#xff1b;前端的 Canvas 就是位图效果&#xff0c;.jpg、.png、.gif格式的文件也是位图。 矢量图&#xff1a;放…

Kubernetes 污点、容忍策略、优先级与抢占、Pod安全

污点 污点使结点与pod产生排斥与标签相反 污点策略是通过嵌入合在键值对上的污点标签进行声明 污点标签必须绑定在键值对上&#xff0c;格式为&#xff1a;keyvalue:[污点标签] taint翻译就是污点的意思 污点标签必须绑定在键值对上&#xff0c;格式为&#xff1a;keyvalue:[污…

《计算机网络——自顶向下方法》精炼——2.5-2.6.1

“Be the change you wish to see in the world.” - Mahatma Gandhi 文章目录 DNSDNS概述DNS的组成DNS的服务 DNS运行过程DNS的分布式数据库本地DNS服务器DNS的运行过程递归查询、迭代查询 DNS缓存DNS记录DNS报文首部区域问题区域回答区域权威区域附加区域 插入DNS记录 P2PP2P…

约瑟夫环的三种解法(循环链表、数组和用数组模拟链表)

目录 前言 一、用循环链表实现 二、用数组实现 三、用数组模拟链表实现 前言 题目描述&#xff1a; 编号为 1 到 n 的 n 个人围成一圈。从编号为 1 的人开始报数&#xff0c;报到 m 的人离开。 下一个人继续从 1 开始报数。 n-1 轮结束以后&#xff0c;只剩下一个人&am…

学系统集成项目管理工程师(中项)系列12_干系人管理

1. 要管理干系人的期望&#xff0c;更要保证他们的适度参与&#xff0c;而后者是项目成功非常关键的因素之一 1.1. 识别干系人及其信息 1.2. 评估关键干系人的诉求和影响力 1.3. 对干系人分类 1.4. 制定干系人管理计划 1.5. 【19上选56】 2. 识别干系人 2.1. 典型干系人…