【设计模式】设计模式之观察者模式

news/2024/9/22 20:44:39/

文章目录

  • 观察者模式
  • 什么是观察者模式
  • 引入
  • 组成
  • UML图
  • 代码实现
    • 1. 定义观察者接口
    • 2. 定义主题接口
    • 3. 实现具体观察者
    • 4. 实现具体被观察者
    • 5.测试
  • 应用场景
  • 优点
  • 缺点

观察者模式

什么是观察者模式

观察者模式(Observer Pattern)是一种设计模式

它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象

使得当一个对象的状态发生改变时,其依赖的其他对象会被自动通知和更新

引入

假如你有两种类型的对象: 顾客商店 。 顾客对某个产品非常感兴趣 , 而该产品很快将会在商店里出售。顾客可以每天来商店看看产品是否到货。 但如果商品尚未到货时, 绝大多数来到商店的顾客都会空手而归。因此,每次产品到货时, 商店可以向订阅的顾客发送邮件。 这样, 顾客就无需反复前往商店

假设有一个微信公众号,当微信公众号发布新文章时,所有关注的用户都会收到推送。

组成

由以下四部分组成:

  1. Subject:抽象主题(抽象被观察者)

    抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者

    抽象主题提供一个接口,可以增加和删除观察者对象。

  2. Concretesubject:具体主题(具体被观察者)

    该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。

  3. observer:抽象观察者(观察者的抽象类)

    它定义了一个更新接口,使得在得到主题更改通知时更新自己.

  4. Concrereobserver:具体观察者

    实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。

UML图

image-20240801210047539

  1. 具体被观察者 会通过notify方法通过遍历List集合向其他对象发送值得关注的事件。 事件会在发布者自身状态改变或执行特定行为后发生。 发布者中包含一个允许新订阅者加入和当前订阅者离开列表的订阅构架。
  2. 观察者 接口声明了通知接口。 在绝大多数情况下, 该接口仅包含一个 update更新方法。 该方法可以拥有多个参数, 使发布者能在更新时传递事件的详细信息。
  3. 具体观察者 可以执行一些操作来回应发布者的通知。 所有具体订阅者类都实现了同样的接口, 因此发布者不需要与具体类相耦合。

代码实现

1. 定义观察者接口

java">// 抽象观察者
public interface Observer {void update(String message);
}

2. 定义主题接口

java">// 抽象主题角色类
public interface Subject {// 添加订阅者(添加观察者对象)void attach(Observer observer);//删除订阅者void detach(Observer observer);//通知订阅者更新消息void notify(String message);
}

3. 实现具体观察者

java">public class User implements Observer {private String name;public User(String name) {this.name = name;}@Overridepublic void update(String message) {System.out.println(name + "接收到:" + message);}
}

4. 实现具体被观察者

java">// 具体主题角色类
public class SubscriptionSubject implements Subject {// 定义一个集合存储观察者对象 观察者集合private List<Observer> userList = new ArrayList<>();@Overridepublic void attach(Observer observer) {userList.add(observer);}@Overridepublic void detach(Observer observer) {userList.remove(observer);}@Overridepublic void notify(String message) {//遍历集合通知观察者for (Observer observer : userList) {observer.update(message);}}
}

5.测试

java">package com.feng.observer;public class Client {public static void main(String[] args) {// 1.创建被观察者对象SubscriptionSubject subject = new SubscriptionSubject();// 2.创建用户对象User user1 = new User("用户1");User user2 = new User("用户2");User user3 = new User("用户3");// 3.进行订阅subject.attach(user1);subject.attach(user2);subject.attach(user3);// 4.被观察者发布subject.notify("公众号更新了");}
}

image-20240801212440080

应用场景

  1. 当一个对象状态的改变需要改变其他对象,或实际对象是事先未知的或动态变化的时,可使用观察者模式
  2. 当应用中的一些对象必须观察其他对象时,可使用该模式。但仅能在有限时间内或特定情况下使用。

优点

  1. 松耦合:观察者和主题之间是松耦合的。主题只知道观察者实现了一个特定的接口,观察者可以自由变化而不影响主题。
  2. 灵活性:可以在运行时添加或删除观察者,灵活应对需求的变化。

缺点

  1. 通知所有观察者的开销:如果观察者很多,通知所有观察者可能会很耗时。
  2. 可能导致循环依赖:如果两个对象互为观察者,可能会导致循环依赖和死循环。


感谢您的阅读
如有错误烦请指正


参考:

  1. 观察者设计模式 (refactoringguru.cn)
  2. 5.设计模式-行为型模式-观察者模式的概述_哔哩哔哩_bilibili

http://www.ppmy.cn/news/1504168.html

相关文章

jdk版本管理利器-sdkman

1.什么是sdkman&#xff1f; sdkman是一个轻量级、支持多平台的开源开发工具管理器&#xff0c;可以通过它安装任意主流发行版本&#xff08;例如OpenJDK、Kona、GraalVM等等&#xff09;的任意版本的JDK。通过下面的命令可以轻易安装sdkman: 2.安装 curl -s "https://…

初识godot游戏引擎并安装

简介 Godot是一款自由开源、由社区驱动的2D和3D游戏引擎。游戏开发虽复杂&#xff0c;却蕴含一定的通用规律&#xff0c;正是为了简化这些通用化的工作&#xff0c;游戏引擎应运而生。Godot引擎作为一款功能丰富的跨平台游戏引擎&#xff0c;通过统一的界面支持创建2D和3D游戏。…

字符专用输入输出函数 getchar() putchar()

文章目录 一、字符专用接收函数1.1 scanf实现字符接收1.2 字符专用接收函数getchar1.3 练习1.4 利用循环使字符接收函数接收字符串的元素 二、字符专用输出函数2.1 printf实现打印字符2.2 字符专用输出函数putchar 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例…

正点原子imx6ull-mini-Linux驱动之platform设备驱动实验(14)

我们在前面几章编写的设备驱动都非常的简单&#xff0c;都是对IO进行最简单的读写操作像I2C、 SPI、LCD 等这些复杂外设的驱动就不能这么去写了&#xff0c;Linux 系统要考虑到驱动的可重用性&#xff0c;因此提出了驱动的分离与分层这样的软件思路&#xff0c;在这个思路下诞生…

python 去除验证码图片噪音

在处理验证码图片时&#xff0c;出现噪音&#xff0c;如横线、像素点等问题往往会影响识别率&#xff0c;这里给出一个去除噪音的方法&#xff0c;仅供学习。 import cv2 import os import numpy as np import copydef del_noise(img, number):height img.shape[0]width img…

torch的register_forward_hook作用

torch的register_forward_hook作用 register_forward_hook 是 PyTorch 提供的一个方法&#xff0c;用于在模型的前向传播过程中注册一个钩子函数。这个钩子函数可以在前向传播过程中对指定层的输入和输出进行操作或记录。它常用于调试、特征提取或修改模型行为。 以下是 regi…

【CSDN平台BUG】markdown图片链接格式被手机端编辑器自动破坏

bug以及解决方法 现在是2024年8月&#xff0c;我打开csdn手机编辑器打算修改一下2023年12月的一篇文章&#xff0c;结果一进入编辑器&#xff0c;源码就变成了下面这个样子&#xff0c;我起初不以为意&#xff0c;就点击了发布&#xff0c;结果图片全部显示不出来了。 而当我修…

一文带你掌握C++模版

12. C模板 什么是模板 模板编程也可以叫做泛型编程&#xff0c;忽略数据类型的一种编程方式 //求最值问题 int Max(int a,int b) {return a>b?a:b; } double Max(int a,int b) {return a>b?a:b; } string Max(string a,string b) {return a>b?a:b; …