Java设计模式之行为型-观察者模式(UML类图+案例分析)

目录

一、基本概念

二、UML类图

三、角色设计

四、代码实现

案例一

案例二

案例三

五、总结


一、基本概念

观察者先订阅被观察者对象,当被观察者的状态发生变化时,观察者可以及时收到消息,在这种模式当中,被观察者维护了一个观察者列表,并提供了添加、删除、通知观察者的方法。

二、UML类图

三、角色设计

角色描述
Blogger被观察者接口(博主),内部提供了注册、删除、通知观察者的方法
CSDNBlogger具体被观察者对象接口的实现类(CSDN),内部维护一个观察者列表
Fans观察者接口(粉丝),在被观察者通知时更新自己
FansObserver具体的观察者,当被通知时,可根据实际需求决定如何更新自己的状态

四、代码实现

这边我分享了三个案例,分别是通过自定义撰写、JDK源码封装和Spring框架封装三种去实现。

案例一

假设有一个被观察者:CSDN博主,它有2个粉丝分别是Jack和Tom,当CSDN发布了通知,对应的粉丝都会收到私信。

1、定义被观察者接口。

public interface Blogger {/*** 新增粉丝*/void addFans(Fans fans);/*** 移除粉丝*/void removeFans(Fans fans);/*** 通知粉丝*/void sendMessage(String message);
}

2、被观察者具体实现类。

CSDN博主:

import java.util.ArrayList;
import java.util.List;public class CSDN implements Blogger {private List<Fans> fansList = new ArrayList<>();@Overridepublic void addFans(Fans fans) {this.fansList.add(fans);}@Overridepublic void removeFans(Fans fans) {this.fansList.remove(fans);}@Overridepublic void sendMessage(String message) {for(Fans fans : fansList){fans.receiveMessage(message);}}
}

3、定义观察者接口。

public interface Fans {void receiveMessage(String message);}

4、定义具体观察者实现类。

Jack粉丝:

public class JackFans implements Fans {@Overridepublic void receiveMessage(String message) {System.out.println("Jack收到了私信:"+message);}
}

Tom粉丝:

public class TomFans implements Fans {@Overridepublic void receiveMessage(String message) {System.out.println("Tom收到了私信:"+message);}
}

5、测试运行:

public class Main {public static void main(String[] args) {Blogger blogger = new CSDN();Fans jackFans = new JackFans();Fans tomFans = new TomFans();blogger.addFans(jackFans);blogger.addFans(tomFans);blogger.sendMessage("CSDN发布了《关于社区整顿的通知》");blogger.removeFans(jackFans);blogger.sendMessage("CSDN发布了《关于博客发布调整的通知》");}
}

6、运行结果:

案例二

这个案例依旧是实现上述逻辑,只不过我们使用JDK提供的接口去实现,过程如下。

1、定义被观察者具体实现类。

CSDN博主:

import java.util.Observable;public class CSDN extends Observable {@Overridepublic void notifyObservers(Object arg) {//修改状态为可以群发setChanged();//调用父类的notifyObservers 群发消息super.notifyObservers(arg);}
}

2、定义观察者具体实现类。

Tom粉丝:

import java.util.Observable;
import java.util.Observer;public class TomFans implements Observer {@Overridepublic void update(Observable o, Object arg) {System.out.println("Tom收到了私信:"+arg);}
}

Jack粉丝:

import java.util.Observable;
import java.util.Observer;public class JackFans implements Observer {@Overridepublic void update(Observable o, Object arg) {System.out.println("Jack收到了私信:"+arg);}
}

3、测试运行:

import java.util.Observable;
import java.util.Observer;public class Main {public static void main(String[] args) {Observable csdn = new CSDN();Observer tomFans = new TomFans();Observer jackFans = new JackFans();csdn.addObserver(tomFans);csdn.addObserver(jackFans);csdn.notifyObservers("《关于整顿社区的通知》");csdn.deleteObserver(tomFans);csdn.notifyObservers("《关于更新CSDN社区的通知》");}
}

4、运行结果:

有了JDK提供的接口去实现,整体代码结构更简洁和方便了! 

案例三

这个案例依旧是上述逻辑,只不过我们这边使用Spring提供的封装事件的监听去实现,这边省去了搭建Spring框架的流程,直接看核心代码就行!

ApplicationEvent和Listener实际上就是Spring基于观察者模式设计的发布-订阅事件模型。

1、ApplicationEvent :自定义的事件对象,用于表示具体的事件。

CSDN博主:

import org.springframework.context.ApplicationEvent;public class CSDN extends ApplicationEvent {private String message;public CSDN(Object source,String message) {super(source);this.message = message;}public String getMessage(){return this.message;}public void setMessage(String message){this.message = message;}}

2、ApplicationListener:事件监听器接口,用于监听特定事件。 

Jack粉丝:

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;@Component
public class JackFans implements ApplicationListener<CSDN> {@Overridepublic void onApplicationEvent(CSDN event) {System.out.println("Jack收到私信:"+event.getMessage());}
}

Tom粉丝: 

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;@Component
public class TomFans implements ApplicationListener<CSDN> {@Overridepublic void onApplicationEvent(CSDN event) {System.out.println("Tom收到私信:"+event.getMessage());}
}

3、单元测试

ApplicationContext:Spring上下文,用于广播ApplicationEvent,并通知相关的ApplicationListener。

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;import javax.annotation.Resource;@SpringBootTest
class ObserverApplicationTests {@Resourceprivate ApplicationContext applicationContext;@Testvoid contextLoads() {CSDN csdn = new CSDN(this,"发布了《关于整顿社区的通知》");applicationContext.publishEvent(csdn);}}

4、运行结果

通过这种方式,不同的业务逻辑模块就可以不依赖于具体的实现,只通过监听特定事件来响应,从而实现解耦。

事件驱动的编程方式还有以下优点:

1、降低耦合度

2、提高模块间的独立性和可重用性

3、易于扩展和维护

总的来说,ApplicationEvent和Listener的设计初衷就是为了解耦和提高系统的扩展性、稳定性。 

五、总结

这边我举了3个案例去更好的理解观察者模式,在我们日常开发的工作中要时刻提醒我们自己的编码思想,利用好这些优秀的前辈提供给我们的精髓,应用到实际业务场景中去,精益求精!

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

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

相关文章

【JUC-6】AQS介绍,基于AQS实现自己的锁

什么是AQS AbstractQueuedSynchronizer(抽象队列同步器&#xff0c;简称AQS)出现在JDK 1.5中。AQS是很多同步器的基础框架&#xff0c;比如ReentrantLock、CountDownLatch和Semaphore等都是基于AQS实现的。除此之外&#xff0c;我们还可以基于AQS&#xff0c;定制出我们所需要…

机器学习11:逻辑回归-Logistic Regression

目录 1.计算概率 2.损失和正则化 2.1 逻辑回归的损失函数 2.2 逻辑回归中的正则化 3.参考文献 1.计算概率 许多问题需要概率估计作为输出。逻辑回归是一种极其有效的概率计算机制。实际上&#xff0c;我们可以通过以下两种方式使用返回的概率&#xff1a; 原始概率&…

git常用命令之远程仓库别名

12. 远程仓库别名 12.1 查看远程仓库名称 命令作用git remote查看关联的远程分支$ git remoteorigingit remote -v查看本地仓库关联的远程仓库信息$ git remote -vorigin gitgithub.com:kaku/reading-note-tutorails.git (fetch)origin gitgithub.com:kaku/reading-note-tuto…

59 KVM Skylark虚拟机混部-概述、架构及特性

文章目录 59 KVM Skylark虚拟机混部-概述、架构及特性59.1 Skylark概述59.1.1 问题背景59.1.2 总体介绍 59.2 架构及特性59.2.1 总体实现框架59.2.2 功耗干扰控制59.2.3 LLC/MB干扰控制59.2.4 CPU干扰控制 59 KVM Skylark虚拟机混部-概述、架构及特性 59.1 Skylark概述 59.1.…

Ubuntu 20.04.02 LTS安装virtualbox7.0

ubuntu22.04的软件仓库也有virtualbox&#xff0c;不过版本较老。 使用安装命令&#xff1a;sudo apt install virtualbox 如果想要安装最新版&#xff0c;那么需要去官网下载deb包或者使用官方的仓库。 这里采用安装Oracle官方仓库的方法。 执行如下命令&#xff1a; wge…

流量分析工具wireshark-学习笔记

&#xff08;一&#xff09;wireshark工具 1、wireshark工具简介 Wireshark是一种开源网络分析工具&#xff0c;它可以让你在计算机网络上捕获和查看数据包&#xff0c;并能帮助你深入了解网络的运行和协议的实现。它可以捕获不同类型的流量&#xff0c;包括以太网、Wi-Fi、TC…

02-独立按键控制LED状态

程序 #include <REGX52.H>void main() {while(1) {if(P3_1 0) //DOWN{P2_0 0xFE;}if(P3_1 1) //UP{P2_0 0XFF;}};}按键的抖动问题 软件实现解决-按键的抖动问题 通过延时解决 #include <REGX52.H>void Delay(unsigned int xms) {while(xms){unsigned cha…

计算机网络————网络层

文章目录 网络层设计思路IP地址IP地址分类IP地址与硬件地址 协议ARP和RARPIP划分子网和构造超网划分子网构造超网&#xff08;无分类编址CIDR&#xff09; ICMP 虚拟专用网VPN和网络地址转换NATVPNNAT 网络层设计思路 网络层向上只提供简单灵活的、无连接的、尽最大努力交付的数…

排序算法--冒泡排序(Java语言)

冒泡排序&#xff08;Bubble Sort&#xff09;是啥&#xff1f; 冒泡排序是一种简单的排序算法。它重复地走访过要排序的元素列&#xff0c;依次比较两个相邻的元素&#xff0c;如果他们的顺序&#xff08;如从大到小、首字母从A到Z&#xff09;错误就把他们交换过来。走访元素…

Idea新建springboot项目遇到的问题及解决

1.更换阿里云 方法&#xff1a; 找到文件路径&#xff1a;Settings > Build,Execution,Deployment > Build Tools > Maven 如下图&#xff1a; 找到相应的settings文件 如果没有就新建一个同名文件&#xff0c;内容如下&#xff1a; <settings xmlns"h…

案例赏析 | 新疆喀什:“大型充电宝”扎根戈壁,让新能源供电更稳定

在喀什&#xff0c;你可以置身秘境&#xff0c;一睹帕米尔高原、乔戈里峰、“冰山之父”慕士塔格峰的壮丽&#xff1b;可以走进喀什古城&#xff0c;在街头巷尾、一砖一瓦间感受丝路风情&#xff1b;可以探访塔克拉玛干沙漠&#xff0c;开始一场关于冒险者的游戏&#xff1b;也…

基于深度学习的高精度绵羊检测识别系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于深度学习的高精度绵羊检测识别系统可用于日常生活中或野外来检测与定位绵羊目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的绵羊目标检测识别&#xff0c;另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5目标检测模型…