行为型设计模式——观察者模式

观察者模式

观察者模式也不难,这个模式用大白话将就是若干个观察者类都订阅一个发布类(被观察者类),当发布者需要发表消息的时候,观察者都能够收到消息。**定义:**又被称为发布-订阅(Publish/Subscribe)模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。

在观察者模式中有如下角色:

  • Subject:抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。
  • ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
  • Observer:抽象观察者,是观察者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。
  • ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。

案例

【例】微信公众号订阅

在使用微信公众号时,大家都会有这样的体验,当你关注的公众号中有新内容更新的话,它就会推送给关注公众号的微信用户端。我们使用观察者模式来模拟这样的场景,微信用户就是观察者,微信公众号是被观察者,有多个的微信用户关注了程序猿这个公众号。

类图如下:

在这里插入图片描述

代码如下:

定义抽象观察者类,里面定义一个更新的方法

public interface Observer {void update(String msg);
}

定义具体观察者类,微信用户是观察者,里面实现了更新的方法

public class WeChatUser implements Observer{private String name;public WeChatUser(String name){this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic void update(String msg) {System.out.println("通过网络将 '"+msg+"' 发送给了"+name);}
}

定义抽象主题类,提供了attach、detach、notify三个方法

public interface Subject {//增加订阅者public void attach(Observer observer);//删除订阅者public void detach(Observer observer);//通知订阅者更新消息public void notify(String message);
}

微信公众号是具体主题(具体被观察者),里面存储了订阅该公众号的微信用户,并实现了抽象主题中的方法。其实这个类只是封装了观察者(订阅者)的操作:

public class SubscriptionSubject implements Subject{//储存订阅公众号的微信用户private List<Observer> weChatUserList = new ArrayList<Observer>();@Overridepublic void attach(Observer observer) {weChatUserList.add(observer);}@Overridepublic void detach(Observer observer) {weChatUserList.remove(observer);}@Overridepublic void notify(String message) {for (Observer o : weChatUserList){o.update(message);}}
}

客户端程序

public class Main {public static void main(String[] args) {// 微信公众号SubscriptionSubject subscriptionSubject = new SubscriptionSubject();// 实例化用户WeChatUser user1 = new WeChatUser("Toy");WeChatUser user2 = new WeChatUser("Jay");WeChatUser user3 = new WeChatUser("Jack");// 订阅公众号subscriptionSubject.attach(user1);subscriptionSubject.attach(user2);subscriptionSubject.attach(user3);// 推送消息subscriptionSubject.notify("抽取iPhone15,就在今天!");}
}

输出结果:

通过网络将 ‘抽取iPhone15,就在今天!’ 发送给了Toy
通过网络将 ‘抽取iPhone15,就在今天!’ 发送给了Jay
通过网络将 ‘抽取iPhone15,就在今天!’ 发送给了Jack

优点

  • 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。
  • 被观察者发送通知,所有注册的观察者都会收到信息【可以实现广播机制】

缺点

  • 如果观察者非常多的话,那么所有的观察者收到被观察者发送的通知会耗时
  • 如果被观察者有循环依赖的话,那么被观察者发送通知会使观察者循环调用,会导致系统崩溃

使用场景

  • 对象间存在一对多关系,一个对象的状态发生改变会影响其他对象。
  • 当一个抽象模型有两个方面,其中一个方面依赖于另一方面时。

JDK中提供的实现

在 Java 中,通过java.util.Observable类和java.util.Observer接口定义了观察者模式,只要实现它们的子类就可以编写观察者模式实例。

1,Observable类

Observable 类是抽象目标类(被观察者),它有一个 Vector 集合成员变量,用于保存所有要通知的观察者对象,下面来介绍它最重要的 3 个方法。

  • void addObserver(Observer o) 方法:用于将新的观察者对象添加到集合中。

  • void notifyObservers(Object arg) 方法:调用集合中的所有观察者对象的 update方法,通知它们数据发生改变。通常越晚加入集合的观察者越先得到通知。

  • void setChange() 方法:用来设置一个 boolean 类型的内部标志,注明目标对象发生了变化。当它为true时,notifyObservers() 才会通知观察者。

2,Observer 接口

Observer 接口是抽象观察者,它监视目标对象的变化,当目标对象发生变化时,观察者得到通知,并调用 update 方法,进行相应的工作。

【例】订阅微信公众号

微信公众号是被观察者,继承java.util.Observable,然后重写几个方法即可,如下:

import java.util.Observable;
import java.util.Observer;
// 微信公众号是发布者(被观察者)
public class SubscriptionSubject extends Observable {String subName; // 公众号名字public SubscriptionSubject(String name){this.subName = name;}public String getSubName() {return subName;}@Overridepublic synchronized void addObserver(Observer o) {System.out.println("微信公众号订阅数+1");super.addObserver(o);}@Overridepublic synchronized void deleteObserver(Observer o) {System.out.println("微信公众号订阅数-1");super.deleteObserver(o);}@Overridepublic void notifyObservers(Object arg) {System.out.println("微信公众号发布文章");super.notifyObservers(arg);}public void publishContent(String msg){System.out.println("发布内容为:"+msg);super.setChanged(); // changed = truenotifyObservers(msg);  // 通知所有订阅者(观察者)}
}

微信用户是一个观察者,所以需要让其实现java.util.Observer接口,重写update方法:

// 微信用户是观察者(订阅者)
public class WeChatUser implements Observer {private String name;public WeChatUser(String name){this.name = name;}public String getName() {return name;}@Overridepublic void update(Observable o, Object arg) {// 由发布者,被观察者o调用,arg 是notifyObservers(msg) 的参数msgString subName = ((SubscriptionSubject) o).getSubName();System.out.println("我是用户"+name+",收到了公众号消息:"+subName+"发来的消息"+(String) arg);}
}

客户端代码

public class Main {public static void main(String[] args) {// 创建公众号(被观察者)SubscriptionSubject sub = new SubscriptionSubject("矩阵科学");// 创建微信用户(观察者)WeChatUser user1 = new WeChatUser("Jay");WeChatUser user2 = new WeChatUser("Tom");WeChatUser user3 = new WeChatUser("Jack");sub.addObserver(user1);sub.addObserver(user2);sub.addObserver(user3);sub.publishContent("欢迎大家关注我的公众号!明天晚上给大家抽iPhone15,谢谢!");sub.deleteObserver(user1);}
}

结果输出:

微信公众号订阅数+1
微信公众号订阅数+1
微信公众号订阅数+1
发布内容为:欢迎大家关注我的公众号!明天晚上给大家抽iPhone15,谢谢!
微信公众号发布文章
我是用户Jack,收到了公众号消息:矩阵科学发来的消息欢迎大家关注我的公众号!明天晚上给大家抽iPhone15,谢谢!
我是用户Tom,收到了公众号消息:矩阵科学发来的消息欢迎大家关注我的公众号!明天晚上给大家抽iPhone15,谢谢!
我是用户Jay,收到了公众号消息:矩阵科学发来的消息欢迎大家关注我的公众号!明天晚上给大家抽iPhone15,谢谢!
微信公众号订阅数-1

参考内容:

传智播客设计模式相关笔记(主要)
https://zhuanlan.zhihu.com/p/77275289

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/236145.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ssm基于Javaweb的物流信息管理系统的设计与实现论文

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统物流信息管理难度大&#xff0c;容错率低&#xff0c;管理…

TOP 10 屏幕录制软件工具,可帮您轻松录制视频!

随着越来越多的人远程工作和学习&#xff0c;对可靠、高效的屏幕录制工具的需求变得越来越重要。屏幕录制已成为电子学习、游戏和视频创作的重要组成部分。然而&#xff0c;有这么多可用的屏幕录制工具&#xff0c;选择合适的工具可能具有挑战性。为了帮助您节省搜索时间和精力…

安达发|APS智能排产系统之换产矩阵

在制造业中&#xff0c;生产计划和调度是至关重要的环节。为了提高生产效率、降低成本并满足客户需求&#xff0c;企业需要采用先进的生产管理系统。APS&#xff08;高级计划与排产&#xff09;智能排产系统正是为此而生的一种解决方案。它通过数学模型和算法&#xff0c;实现了…

软件测试|Docker exec命令详细使用指南

简介 Docker exec命令是Docker提供的一个强大工具&#xff0c;用于在正在运行的容器中执行命令。本文将详细介绍Docker exec命令的用法和示例&#xff0c;帮助大家更好地理解和使用这个命令。 Docker是一种流行的容器化平台&#xff0c;允许我们在容器中运行应用程序。有时候…

k8s-----存储卷(数据卷)

容器内的目录和宿主机的目录进行挂载。 容器的生命状态是短站的&#xff0c;delete删除&#xff0c;k8s用控制创建的pod&#xff0c;delete相当于重启&#xff0c;容器的状态也会回复到初始状态。 一旦回到初始状态&#xff0c;所有的后天编辑的文件都会消失。 容器和节点之间创…

vue的mvvm模式

1.mvvm优点&#xff1a; 低耦合&#xff1a;视图&#xff08;View&#xff09;可以独立于Model变化和修改&#xff0c;一个ViewModel可以绑定到不同的View上&#xff0c;当View变化的时候Model可以不变&#xff0c;当Model变化的时候&#xff0c;View也可以不变。 可复用&…

ASP.NET Core中实现个人资料上传图片功能

当用户需要在ASP.NET Core中实现修改个人资料的功能时&#xff0c;其中一个常见的需求就是允许上传个人头像图片。下面将详细介绍如何在ASP.NET Core中实现修改个人资料上传图片的功能。 步骤一&#xff1a;控制器中添加一个HttpPost方法 首先&#xff0c;我们在控制器中添加…

Vue入门五(Vue-CLI项目搭建|vue项目目录介绍|vue项目开发规范|es6导入导出语法)

文章目录 一、Vue-CLI 项目搭建介绍node环境搭建1) 下载与安装2&#xff09;测试是否安装成功 安装vue-cli安装vue脚手架 创建Vue项目1&#xff09;使用命令创建项目2&#xff09;使用图形化界面创建项目 二、vue项目目录介绍1.命令行运行vue项目2.Pycharm中运行项目3.目录结构…

2023年全国职业院校技能大赛软件测试赛题—单元测试卷④

任务二 单元测试 一、任务要求 题目1&#xff1a;根据下列流程图编写程序实现相应分析处理并显示结果。返回结果“ax&#xff1a;”&#xff08;x为2、3或4&#xff09;&#xff1b;其中变量x、y均须为整型。编写程序代码&#xff0c;使用JUnit框架编写测试类对编写的程序代码…

系列十三、查询数据库中某个库、表、索引等所占空间的大小

一、information_schema数据库 1.1、概述 information_schema数据库是MySQL出厂默认带的一个数据库&#xff0c;不管我们是在Linux中安装MySQL还是在Windows中安装MySQL&#xff0c;安装好后都会有一个数据库information_schema&#xff0c;这个库中存放了其他库的所有信息。 …

JS加密/解密之js加密小工具

JS加密的原理和方法 什么是JS加密 JS加密是一种将js代码转换成不易被阅读和修改的形式的技术JS加密的目的是保护js代码的版权&#xff0c;防止被恶意篡改或盗用JS加密的难度和效果取决于加密算法的复杂性和安全性 JS加密的常见方法 压缩和混淆&#xff1a;将js代码的空格&a…

17_网络编程

文章目录 网络数据传输的基本原理UDP发送端步骤接收端步骤DatagramSocketDatagramPacket举例版本1&#xff1a;发送端发送消息,接收端接收并打印版本2&#xff1a;创建一个NetworkUtils工具类优化版本1版本3&#xff1a;发送端接收端相互发送版本4&#xff1a;使用多线程 TCP客…

搭建LNMP网站平台并部署Web应用

本章主要介绍&#xff1a; 安装Nginx安装MySQL安装PHP在LNMP平台中部署 Web 应用 构建LNMP网站平台就像构建LAMP平台一样&#xff0c;构建LNMP平台也需要Linux服务器&#xff0c;MySQL数据库&#xff0c;PHP解析环境&#xff0c;区别主要在Nginx 与 PHP的协作配置上&#xff0…

Kotlin程序设计(三)高级用法

Kotlin程序设计高级篇 在学习了前面的内容之后&#xff0c;相信各位小伙伴应该对Kotlin这门语言有了一些全新的认识&#xff0c;我们已经了解了大部分的基本内容&#xff0c;从本章开始&#xff0c;就是对我们之前所学的基本内容的进一步提升。 泛型 在前面我们学习了最重要…

缓存代理服务器

1 缓存代理 1.1 缓存代理的概述 web代理的作用 缓存网页对象&#xff0c;减少重复请求 存储一些之前被访问的或且可能将要备再次访问的静态网页资源对象&#xff0c;使用户可以直接从缓存代理服务器获取资源&#xff0c;从而减少上游原始服务器的负载压力&#xff0c;加快整…

ubuntu20固定串口名称

查看串口的详细信息 udevadm info --name/dev/ttyUSB0结果&#xff1a; P: /devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1.2/1-1.2:1.0/ttyUSB0/tty/ttyUSB0 N: ttyUSB0 L: 0 S: serial/by-id/usb-Silicon_Labs_CP2102_USB_to_UAR…

Qt 6之五:创建菜单

Qt 6之五&#xff1a;创建菜单 Qt是一种跨平台的C应用程序开发框架&#xff0c;它提供了一套丰富的工具和库&#xff0c;可以帮助开发者快速构建跨平台的应用程序&#xff0c;用于开发图形用户界面&#xff08;GUI&#xff09;和非GUI应用程序。 Qt 6之一&#xff1a;简介、安…

DHCP动态主机配置协议

文章目录 DHCP1、DHCP的优势2、DHCP的分配方式3、DHCP的租约过程4、服务器配置命令格式命令图文详解 DHCP DHCP&#xff1a;动态主机配置协议 1、DHCP的优势 减少管理员的工作量 避免输入错误的可能 避免IP地址冲突 当更改IP地址段时&#xff0c;不需要重新配置每个用户的…

Qt 三维柱状图 Q3DBar 和 三维条形图中的数据序列 QBar3DSeries

(一) 使用 Q3DBars 图形类和 QBar3DSeries 序列类可以绘制三维柱状图 窗口右侧是用 Q3DBars 和 QBar3DSeries 绘制的三维柱状图&#xff0c;这个图只有一个QBar3DSeries序列&#xff0c;数据是按行存储的&#xff0c;可以有多行。水平方向是行坐标轴和列坐标轴&#xff0c;使用…

阿里云服务器新购、续费、升级优惠政策与活动汇总

阿里云作为国内领先的云服务提供商&#xff0c;始终致力于为客户提供优质、高效的服务。为了更好地满足客户的需求&#xff0c;阿里云经常推出各种优惠政策与活动。本文将为大家详细介绍阿里云服务器的新购、续费、升级优惠政策与优惠活动&#xff0c;帮助大家更好地了解并利用…