观察者模式
GOF概括:定义对象间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都得到通知并被自动更新。
概述
这个可能是最早接触,但是,越学越复杂的设计模式了。
主要是因为 “观察者模式” 可以引申出非常多的知识点:“发布-订阅者模式”、“消息队列”……
观察者模式是非常重要的一个设计模式,你几乎能在任何项目见到观察者模式的应用,并且会伴随着程序员走完整个职业生涯。
- 简单地说,就是一个对象,做了某件事,另一个对象要接着做点啥;
- 往大了说,卫星拍了一张照,新闻上你可能看到,天气系统也能看到(一个系统更新消息,无数下游的服务需要侦听消息变化);
- 往小了说,就比如你 update 一条数据,日志系统要记录你的操作(一个模块的更新,另一个模块随之变化)。
推送场景
这种代码结构非常常见,基本是要求背诵的。
一下子就能想到的,就是各种点击事件,例如:xxxClickListener(Event e)。
import java.util.ArrayList;
import java.util.List;
interface Observer{
// 侦听函数
void onAction(String action);
}
class Subject{
// 观察者集合
List<Observer> list = new ArrayList<>();
// 一个业务流
public void run(){
// do sth.
// then
notifyObserver("ok");
}
// 做完一件事情之后,触发所有观察者的侦听函数
public void notifyObserver(String action){
for(Observer observer: list){
observer.onAction(action);
}
}
}
拉取场景
拉取模式与推送模式的区别是:收到消息之后,可以根据需求,拉取不同的数据。
说实话,对于 “拉取模式” 这个词,我是有些怀疑的,像是老师为了为难学生,自己创造出来的名词。
- 首先,代码本身就有点不伦不类的感觉,Observer 必须 import Subject,观察者与主题之间产生了耦合,正常应该只与消息产生耦合;
- 然后,去找 “观察者模式” 的文章,经常看不到 “拉取模式” 的相关内容;
- 最后,这并没有改变 “推送模式” 的本质,就比如下面代码,把 getMsg1() 放到另一个类,代码还是标准的推送模式。
不管具体怎样,不排除面试时,可能有人会这么问你,很多人都是这么学的,所以还是要掌握一下。
import java.util.ArrayList;
import java.util.List;
class Observer{
// 一个侦听函数
public void onAction(Subject action){
System.out.println(action.getMsg1());
}
}
class Subject{
List<Observer> list = new ArrayList<>();
// 一个业务流
public void run(){
// do sth.
notifyObserver();
}
// 获取消息 a
public String getMsg1(){
return "message1";
}
// 获取消息 b
public String getMsg2(){
return "message2";
}
// 通知所有的观察者
public void notifyObserver(){
for(Observer observer: list){
observer.onAction(this);
}
}
}
JDK标准实现
JDK 的 java.util 包提供了标准接口,可能整个职业生涯都用不上,
当然,多少要了解一些,因为面试可能会被提问。
实在不想了解,可以这么和面试官解释:因为 java 是单继承,Observable 的设计注定不会太实用;
业务上,需求往往十分复杂,使用 Observable 这样一个不常用、又很复杂的类,可能会增加维护负担。
一些文章认为,JDK 的实现是拉取模式,因为 update() 第一个参数是 Observable,
但是实际上,一个观察者,可以侦听很多消息,Observable 本身就是必要的,需要用它确定消息来源。
import java.util.Observable;
import java.util.Observer;
class Obs implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println(o);
System.out.println(arg);
}
}
class Subject extends Observable{
public void run(){
// do sth.
super.setChanged();
super.notifyObservers("msg");
}
}
public class Test2 {
public static void main(String[] args) {
Obs obs = new Obs();
Subject subject = new Subject();
subject.addObserver(obs);
subject.run();
}
}
疯狂的妞妞 :每一天,做什么都好,不要什么都不做!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY