观察者模式

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();
    }
}

posted on   疯狂的妞妞  阅读(132)  评论(0编辑  收藏  举报

(评论功能已被禁用)
编辑推荐:
· 开发者必知的日志记录最佳实践
· 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
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示