Java设计模式—观察者模式

news/2025/1/24 7:41:14/

观察者模式

目录

1、什么是观察者模式

  - 实例:现实生活中很多事物都是依赖存在的,一个发生变化会影响很多事物。比如油价上涨,关系很多企业,很多家庭;红绿灯发生变化时,人们会停止,会前进等。
  - 观察者模式 (Observer Pattern) :是一种一对多的依赖关系,让多个观察对象同时监听某一个主题对象,当主题对象的状态发生变化时,会自动通知所有观察者,使得它们能够自动更新自己。适用于当一个对象的状态发生改变时,所有依赖于它的对象都需要得到通知的情况。
  - 观察者模式具体的角色 :实现观察者模式时要注意具体目标对象和具体观察者对象之间不能直接调用,否则将使两者之间紧密耦合起来,这违反了面向对象的设计原则。

  • 抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
  • 具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。继承Subject类,在这里实现具体业务,在具体项目中,该类会有很多变种。
  • 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
  • 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。

2、观察者模式优缺点及注意事项?

- 优点:
  1.降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系.符合依赖倒置原则
  2.目标与观察者之间建立了一套触发机制
- 缺点:
  1.目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用
  2.当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率
- 注意事项:
  1.JDK8 中java.util.Observable 类和 java.util.Observer 接口定义了观察者模式,后面版本舍弃了,因为在使用异步处理的情况下,线程不安全。
  2.要注意循环调用情况,避免死锁。
  3.可以去观察消息队列实现,典型的观察者模式实现。

3、观察者模式实现?

模仿jdk8中 Observable 类 和 Observer接口实现
- 目标类

java">public class Subject {private Vector<Observer> obs = new Vector<>();public void addObserver(Observer o) {if (o == null)throw new NullPointerException();if (!obs.contains(o)) {obs.add(o);}}public void deleteObserver(Observer o) {obs.remove(o);}public void notifyObservers() {for(Observer observer : this.obs) {observer.resopnse();}}
}

- 具体实现目标类

java">public class ConcreteSubject extends Subject{// 具体实现public void doSomethings(){// 一些其它逻辑处理System.out.println("-----被观察者发生了改变------");super.notifyObservers();}
}

- 观察者类

java">public interface Observer {// 响应void resopnse();
}

- 具体观察者类

java">public class ConcreteObserver implements Observer{private int num;public ConcreteObserver(int num) {this.num = num;}@Overridepublic void resopnse() {System.out.println("观察者"+num+"做出改变");}
}

- 执行任务

java">public class Main {public static void main(String[] args) {
// ---------------  观察者模式  -----------------// 先创建多个观察者ConcreteSubject concreteSubject = new ConcreteSubject();for (int a = 0; a < 10; a++) {concreteSubject.addObserver(new ConcreteObserver(a+1));}concreteSubject.doSomethings();}

4、手写线程安全的观察者模式

设定场景:手机花费快没钱了,运营商通知你要缴费了。 这里运营商就是被观察者,用户就是观察者,用户的手机号就是注册的一个过程,运营商通知用户。

使用jdk中com.util.concurrent提供的线程安全的类:CountDownLatch,CountDownLatch就一个线程同步工具,它相当于一个倒序计数器,用来协调多个线程的执行。多个线程通过调用它们所共享的计数器CountDownLatch的countDown方法来让计数器减1。通过await方法来阻塞当前线程,直到计数器变成0。达到线程阻塞直至其他线程执行完成被重新唤醒。主要有三个方法:
1.构造函数,初始化state的值,state等于同步线程数
2.await(),让线程阻塞
3.countDown(),计数器(state)减1的方法。

java">public class Main {public static void main(String[] args) {// ---------------  安全的观察者模式 --------------// 设定场景:手机花费快没钱了,运营商通知你要缴费了。  这里运营商就是被观察者,用户就是观察者,用户的手机号就是注册的一个过程,运营商通知用户。ConcreteTelecomOperator telecomOperator = new ConcreteTelecomOperator("中国电信");telecomOperator.addUser(new ConcreteUser("张三"));telecomOperator.addUser(new ConcreteUser("李四"));telecomOperator.addUser(new ConcreteUser("王五"));telecomOperator.addUser(new ConcreteUser("小明"));telecomOperator.doSomeThing("通知您,您已欠费请及时缴费。祝你生活愉快!");}
}
java">/*** @program: practice_tools* @description: 运营商目标类* @author: tiezhu* @create: 2025-01-20 09:58**/
public class TelecomOperator {private String name;private ConcurrentMap<String, User> obs;public TelecomOperator(String name) {this.name = name;obs = new ConcurrentHashMap<>();}public void addUser(User u){if (u == null)throw new NullPointerException();if (!obs.containsKey(u.getName())) {obs.put(u.getName(),u);}}public void removeUser(User u){obs.remove(u.getName());}public void notifyObservers(String content) {try {long beginTime = System.currentTimeMillis();CountDownLatch latch = new CountDownLatch(obs.size());for (User user : obs.values()) {user.response(content);latch.countDown();}latch.await();long endTime = System.currentTimeMillis();System.out.println(name + "消息发送完毕,耗时:" + (endTime - beginTime));System.out.println();} catch (InterruptedException e) {e.printStackTrace();}}
}
java">/*** @program: practice_tools* @description: 具体目标类* @author: tiezhu* @create: 2025-01-20 11:43**/
public class ConcreteTelecomOperator extends TelecomOperator{public ConcreteTelecomOperator(String name) {super(name);}public void doSomeThing(String content){System.out.println("开始发布信息:");super.notifyObservers(content);}
}
java">/*** 用户观察者*/
public interface User {void response(String content);String getName();
}
java">/*** @program: practice_tools* @description: 观察者实体类* @author: tiezhu* @create: 2025-01-20 10:04**/
public class ConcreteUser implements User{private String name;public ConcreteUser(String name) {this.name = name;}@Overridepublic void response(String content) {System.out.println("接收到了消息为:"+content);System.out.println(name + "准备去缴费了");}@Overridepublic String getName() {return name;}
}

结果:执行结果和创建顺序不同,不用按照创建顺序执行完再执行了。
在这里插入图片描述


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

相关文章

专业学习|最优化理论(目标函数、约束条件以及解题三板斧)

个人学习使用资料,请勿传播,若有侵权联系删除,资料来源:fairy girl。 一、最优化理论:让决策更科学,让模型更高效 (一)什么是最优化理论? 最优化理论是数学的一个分支,它研究如何在一定约束条件下找到使目标函数达到最大值或最小值的最优解。 关键概念:最优化理论的…

rclone整合alist

rclone整合alist 安装/配置rclone脚本安装rcloneetc/systemd/system/rclonehttp.serviceetc/systemd/system/rclone-alist.serviceconfig授权下载HTTP web介面文件启用服务并设置开机启动 安装/配置rclone 脚本安装rclone sudo -v ; curl https://rclone.org/install.sh | su…

【MySQL】存储引擎有哪些?区别是什么?

频率难度60%⭐⭐⭐⭐ 这个问题其实难度并不是很大&#xff0c;只是涉及到的相关知识比较繁杂&#xff0c;比如事务、锁机制等等&#xff0c;都和存储引擎有关系。有时还会根据场景选择不同的存储引擎。 下面笔者将会根据几个部分尽可能地讲清楚 MySQL 中的存储引擎&#xff0…

深度学习-92-大语言模型LLM之基于langchain的模型IO的模型调用

文章目录 1 Model的输入输出2 langchain支持的模型3 调用Ollama模型3.1 设置环境变量3.2 大语言模型LLM(OllamaLLM)3.2.1 生成文本补全3.2.2 流式生成文本补全3.3 聊天模型(ChatOllama)3.3.1 内置的消息类型3.3.2 HumanMessage和SystemMessage3.3.3 元组方式构成消息列表3.3.4 …

【Trunk接口配置】

Trunk接口配置 Trunk即干道链路&#xff0c;用来在不同设备&#xff08;交换机和交换机&#xff0c;交换机和路由器&#xff09;间承载所有vlan数据。不属于任何一个具体的vlan&#xff0c;可以传输所有vlan的数据&#xff0c;也可以传输指定vlan的数据。 设备IPvlanPC110.1.…

ceph新增节点,OSD设备,标签管理(二)

一、访问客户端集群方式 方式一: 使用cephadm shell交互式配置 [rootceph141 ~]# cephadm shell # 注意&#xff0c;此命令会启动一个新的容器&#xff0c;运行玩后会退出&#xff01; Inferring fsid c153209c-d8a0-11ef-a0ed-bdb84668ed01 Inferring config /var/lib/ce…

Qt 5.14.2 学习记录 —— 십구 事件

文章目录 1、事件的概念2、处理事件3、鼠标事件1、鼠标单击和双击2、鼠标移动3、鼠标滚轮滚动 4、键盘事件5、定时器事件6、窗口移动和大小改变事件 1、事件的概念 用户进行操作时会产生事件&#xff0c;事件可以关联处理函数。Qt封装了操作系统的事件机制&#xff0c;然后进一…

[STM32 - 野火] - - - 固件库学习笔记 - - -十一.电源管理系统

一、电源管理系统简介 电源管理系统是STM32硬件设计和系统运行的基础&#xff0c;它不仅为芯片本身提供稳定的电源&#xff0c;还通过多种电源管理功能优化功耗、延长电池寿命&#xff0c;并确保系统的可靠性和稳定性。 二、电源监控器 作用&#xff1a;保证STM32芯片工作在…