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

news/2025/1/31 4:44:59/

Observer Pattern

1、定义

观察者模式是一种设计模式,它定义了对象之间的一对多依赖关系。当一个对象的状态发生改变时,它的所有依赖对象都会收到通知并自动更新。

在观察者模式中,有两个主要角色:被观察者和观察者。被观察者维护了一个观察者列表,并提供了添加和删除观察者的方法。当被观察者的状态发生改变时,它会遍历观察者列表并调用每个观察者的更新方法,通知它们状态的改变。

观察者模式可以被应用于许多场景中,例如用户界面组件、事件处理等。它使得对象之间的耦合度降低,因为被观察者不需要知道观察者的具体实现,而只需要通知它们即可。同时,观察者模式也提高了代码的可维护性和可扩展性,因为可以方便地添加或移除观察者,而不需要修改被观察者的代码。

2、优缺点

优点:

  1. 松耦合性:观察者模式实现了松耦合,使得观察者和主题之间的依赖关系变得比较小,各自可以独立地进行扩展。
  2. 可重用性:观察者模式使得主题和观察者之间的关系可以被复用,不需要修改原有代码即可增加新的观察者。
  3. 支持广播通信:观察者模式支持广播通信,当主题对象发生改变时,会向所有的观察者发送通知,保证所有观察者对象的状态都是最新的。

缺点:

  1. 观察者过多导致性能问题:如果观察者数量过多或者观察者的处理时间过长,会降低系统的性能。
  2. 顺序执行问题:观察者模式中,各个观察者是按照添加的顺序执行的,如果观察者之间有依赖关系,可能会导致程序出现问题。
  3. 异常处理问题:如果一个观察者出现了异常,可能会影响整个系统的稳定性。

3、比喻了解

观察者模式可以通过生活中的例子来理解。

假设你是一位球迷,你想要及时了解你最喜欢的足球队的比赛成绩。于是你订阅了这个足球队的官方网站,并将其作为观察者。当这个足球队的比赛结果出来后,官方网站就会向你发送通知,告诉你比赛的结果。

在这个例子中,足球队就是主题对象,而球迷就是观察者。球迷可以随时取消订阅,也可以同时订阅多个足球队的官方网站,这就体现了观察者模式中的松耦合性和可重用性。同时,足球队可以向所有订阅者广播比赛结果,这就体现了观察者模式中的广播通信特性。

总的来说,观察者模式就是一个对象(即主题)发生变化时,其他对象(即观察者)能得到通知并自动更新,从而实现对象之间的松耦合、可重用性和广播通信等特性。

4、代码示例

import java.util.ArrayList;interface Subject {void registerObserver(Observer observer);void removeObserver(Observer observer);void notifyObservers(String message);
}interface Observer {void update(String message);
}class NewsPaper implements Subject {private ArrayList<Observer> observers = new ArrayList<>();public void registerObserver(Observer observer) {observers.add(observer);}public void removeObserver(Observer observer) {observers.remove(observer);}public void notifyObservers(String message) {for (Observer observer : observers) {observer.update(message);}}public void setNews(String news) {System.out.println("今日新闻:" + news);notifyObservers(news);}
}class Reader implements Observer {private String name;public Reader(String name) {this.name = name;}public void update(String message) {System.out.println(name + "收到新闻:" + message);}
}public class ObserverDemo {public static void main(String[] args) {NewsPaper newspaper = new NewsPaper();Reader reader1 = new Reader("小明");Reader reader2 = new Reader("小红");newspaper.registerObserver(reader1);newspaper.registerObserver(reader2);newspaper.setNews("中国女排夺冠了!");// 输出:// 今日新闻:中国女排夺冠了!// 小明收到新闻:中国女排夺冠了!// 小红收到新闻:中国女排夺冠了!}
}

在这个示例中,NewsPaper是主题接口,Reader是观察者接口。NewsPaper实现了主题接口,包含了注册、移除和通知观察者的方法。

Reader实现了观察者接口,包含了更新状态的方法。在main方法中,我们创建了一个NewsPaper对象和两个Reader对象,并将两个Reader对象注册到NewsPaper中。当NewsPaper的新闻发生改变时,它会通知所有的观察者,并调用它们的update方法。最终,输出结果表明两个Reader对象都收到了这条新闻。

class Subject {constructor() {this.observers = [];}registerObserver(observer) {this.observers.push(observer);}removeObserver(observer) {const index = this.observers.findIndex((o) => o === observer);this.observers.splice(index, 1);}notifyObservers(message) {for (const observer of this.observers) {observer.update(message);}}
}class NewsPaper extends Subject {constructor() {super();this.news = "";}setNews(news) {console.log(`今日新闻:${news}`);this.news = news;this.notifyObservers(news);}
}class Reader {constructor(name) {this.name = name;}update(message) {console.log(`${this.name}收到新闻:${message}`);}
}const newspaper = new NewsPaper();const reader1 = new Reader("小明");
const reader2 = new Reader("小红");newspaper.registerObserver(reader1);
newspaper.registerObserver(reader2);newspaper.setNews("中国女排夺冠了!");
// 输出:
// 今日新闻:中国女排夺冠了!
// 小明收到新闻:中国女排夺冠了!
// 小红收到新闻:中国女排夺冠了!

在这个示例中,Subject是主题类,包含了注册、移除和通知观察者的方法。NewsPaper继承自Subject,实现了设置新闻和记录新闻的功能。

Reader是观察者类,包含了更新状态的方法。在代码的最后,我们创建了一个NewsPaper对象和两个Reader对象,并将两个Reader对象注册到NewsPaper中。当NewsPaper的新闻发生改变时,它会通知所有的观察者,并调用它们的update方法。最终,输出结果表明两个Reader对象都收到了这条新闻。


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

相关文章

python中函数与类 类中的方法-静态方法/动态方法

class student():position即令def __init__(self,name,age):self.namenameself.ageagedef eat(self):passclassmethoddef cla(cls):passstaticmethoddef sta():passpassstustudent(name张三,age12) print(stu.position)stu.sta() stu.cla()# 直接使用静态和类方法 student.cla(…

【PSO-LSTM】基于PSO优化LSTM网络的电力负荷预测(Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

linux内核调试的几个方法

参考 以下内容&#xff1a; Linux 笔记&#xff1a; https://xuesong.blog.csdn.net/article/details/109522945?spm1001.2014.3001.5502 printk: printk在内核源码中用来记录日志信息的函数&#xff0c;只能在内核源码范围内使用。用法和printf非常相似&#xff1b; printk…

delete方法删除对象数组中元素导致原始数据被修改

记录一个自己在码代码过程中遇到的问题。 要求&#xff1a;删除数组对象中每一组对象中的一个属性。 下面是我原始的写法(当然是错误的)。 const { log } require("console");// 用于测试delete方法&#xff0c;删除对象中的指定元素 const testForDelete () >…

Problem E. 矩阵游戏 (2023年ccpc河南省赛)

原题链接&#xff1a; https://codeforces.com/gym/104354 题意&#xff1a; 有一个n*m的矩阵&#xff0c;只有三种字符&#xff1a;0,1和?。从[1,1]走到[n,m],每次只能向下走或者向下走。当走到1的时候得一分&#xff0c;走到0的时候不得分&#xff0c;走到?的时候可以将他…

linux中查看某个文件夹下文件的个数和大小

一、统计某个目录的文件和子目录的大小 1、stat指令 stat命令 主要用于显示文件或文件系统的详细信息&#xff0c;该命令的语法格式如下&#xff1a; -f  不显示文件本身的信息&#xff0c;显示文件所在文件系统的信息-L  显示符号链接-t  简洁模式&#xff0c;只显示…

WuThreat身份安全云-TVD每日漏洞情报-2023-05-08

漏洞名称:SBS20 SCANSERVJS 命令注入 漏洞级别:严重 漏洞编号:CVE-2023-2564 相关涉及:SBS20 SCANSERVJS 之前的 2.27.0 漏洞状态:POC 参考链接:https://tvd.wuthreat.com/#/listDetail?TVD_IDTVD-2023-11118 漏洞名称:Parallels Desktop for Mac Toolgate组件路径穿越漏洞 漏…

python中字符分割为列表,以及将列表中的字符串转为数字

目录 1、字符分割为列表 2、将列表中的字符串转为数字 3、map() 函数 1、字符分割为列表 a "1 2 3 4 5 6" b a.split( ) print(b)# [1, 2, 3, 4, 5, 6] 2、将列表中的字符串转为数字 a [1, 2, 3, 4, 5, 6] b list(map(int,a)) print(b)# [1, 2, 3, 4, 5, 6…