Code Ease Code Ease
  • 个人博客网站 (opens new window)
  • 好用的工具网站 (opens new window)
  • Java核心基础
  • 框架的艺术
  • 分布式与微服务
  • 开发经验大全
  • 设计模式
  • 版本新特性
数据库系列
大数据+AI
  • xxl-job
运维与Linux
  • 基于SpringBoot和BootStrap的论坛网址
  • 基于VuePress的个人博客网站
  • 基于SpringBoot开发的小功能
  • 做一个自己的IDEA插件
程序人生
关于我
  • 分类
  • 标签
  • 归档

神秘的鱼仔

你会累是因为你在走上坡路
  • 个人博客网站 (opens new window)
  • 好用的工具网站 (opens new window)
  • Java核心基础
  • 框架的艺术
  • 分布式与微服务
  • 开发经验大全
  • 设计模式
  • 版本新特性
数据库系列
大数据+AI
  • xxl-job
运维与Linux
  • 基于SpringBoot和BootStrap的论坛网址
  • 基于VuePress的个人博客网站
  • 基于SpringBoot开发的小功能
  • 做一个自己的IDEA插件
程序人生
关于我
  • 分类
  • 标签
  • 归档
服务器
  • 适配器模式详解与应用
  • 迭代器模式:理解与实践
  • 模板方法设计模式理论与应用
  • 快速理解工厂方法模式,及其在源码中的应用
  • 详解单例模式及其在Sping中的最优实践
  • 快速理解原型模式,及其在源码中的应用
  • 快速理解建造者模式,及其在JDK源码中的应用
  • 最实用的设计模式:策略模式的快速理解
  • 快速理解装饰者模式,及其在JDK源码中的应用
  • 快速理解观察者模式,原来它还有这么多其他名字
    • (一)什么是观察者模式
    • (二)观察者模式中的角色
    • (三)观察者模式的案例
    • (四)观察者模式在源码中的应用
    • (五)总结
  • 设计模式
CodeEase
2023-10-24
目录

快速理解观察者模式,原来它还有这么多其他名字

作者:鱼仔
博客首页: codeease.top (opens new window)
公众号:Java鱼仔

# (一)什么是观察者模式

我们都关注了某个公众号,当这个公众号发文章时,所有关注它的人都会收到一条消息通知。这种当一个对象被修改时,会自动通知依赖它的对象的动作抽象为设计模式就是观察者模式

# (二)观察者模式中的角色

观察者模式中主要有四个角色:

Subject:被观察对象的抽象类,这个角色还承担了注册观察者和删除观察者的方法。

ConcreteSubject:具体的被观察对象,在开头的例子中,某个公众号就是一个具体的被观察对象。

Observer:观察者的接口,负责接收被观察对象的状态变化并更新。

ConcreteOberver:具体的观察者,在开头的例子中,每个关注公众号的人就是具体的观察者。

# (三)观察者模式的案例

只看概念很难理解这种设计模式究竟是干什么的,接下来就通过一个具体的例子来感受一下,这个例子还是采用文章开头公众号的例子。 首先定义Observer接口,负责更新操作。

public interface Observer {
    /**
     * 更新操作
     * @param subject
     */
    public abstract void update(Subject subject);
}
1
2
3
4
5
6
7

上面代码中的Subject是被观察对象的抽象类,这个类定义了添加观察者、删除观察者、通知观察者的方法,并定义了获取标题和生成文章的两个抽象方法:

public abstract class Subject {
    /**
     * 记录所有的观察者
     */
    private ArrayList<Observer> observers = new ArrayList<>();
    /**
     * 添加观察者
     * @param observer
     */
    public void addObservers(Observer observer){
        observers.add(observer);
    }
    /**
     * 删除观察者
     * @param observer
     */
    public void deleteObservers(Observer observer){
        observers.remove(observer);
    }
    /**
     * 通知所有的观察者
     */
    public void notifyObservers(){
        for(Observer observer:observers){
            observer.update(this);
        }
    }
    /**
     * 获取文章标题
     */
    public abstract String getTitle();
    /**
     * 生成一篇文章
     */
    public abstract void createArticle();
}
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
32
33
34
35
36

接着定义具体的被观察对象,这里是一个具体的公众号,并实现获取标题和创建文章的抽象方法:

public class ConcreteSubject extends Subject{
    private String title;
    @Override
    public String getTitle() {
        return title;
    }

    @Override
    public void createArticle() {
        System.out.println("创建了一篇文章");
        this.title="这是文章标题";
        this.notifyObservers();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

接下来创建两个观察者:

public class OneObserver implements Observer{
    @Override
    public void update(Subject subject) {
        System.out.println("One收到了一篇推送,标题为"+subject.getTitle());
    }
}

public class TwoObserver implements Observer{
    @Override
    public void update(Subject subject) {
        System.out.println("Two收到了一篇推送,标题为"+subject.getTitle());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

最后通过Main类进行测试:

public class Main {
    public static void main(String[] args) {
        //创建具体的被观察者对象
        Subject concreteSubject = new ConcreteSubject();
        //创建两个具体的观察者
        Observer oneObserver = new OneObserver();
        Observer twoObserver = new TwoObserver();
        //两个具体的观察者关注了被观察者对象
        concreteSubject.addObservers(oneObserver);
        concreteSubject.addObservers(twoObserver);
        //被观察者对象创建了一篇文章
        concreteSubject.createArticle();
        //第一个观察者取消关注
        concreteSubject.deleteObservers(oneObserver);
        //被观察者对象又创建了一篇文章
        concreteSubject.createArticle();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

最终的运行结果如下:

创建了一篇文章
One收到了一篇推送,标题为这是文章标题
Two收到了一篇推送,标题为这是文章标题
创建了一篇文章
Two收到了一篇推送,标题为这是文章标题
1
2
3
4
5

# (四)观察者模式在源码中的应用

在JDK的java.util包下,直接提供了观察者模式所需要的Observer和Subject对象。其中Observer对象和我在第三章定义的十分相似:

package java.util;

public interface Observer {
    void update(Observable o, Object arg);
}
1
2
3
4
5

Subject对象在这个包下名称叫做Observable,包含了添加观察者,删除观察者等操作。

package java.util;

public class Observable {
    private boolean changed = false;
    private Vector<Observer> obs;

    public Observable() {
        obs = new Vector<>();
    }

    public synchronized void addObserver(Observer o) {
        if (o == null)
            throw new NullPointerException();
        if (!obs.contains(o)) {
            obs.addElement(o);
        }
    }

    public synchronized void deleteObserver(Observer o) {
        obs.removeElement(o);
    }

    public void notifyObservers() {
        notifyObservers(null);
    }
    public void notifyObservers(Object arg) {
        Object[] arrLocal;

        synchronized (this) {
            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }

        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }
    public synchronized void deleteObservers() {
        obs.removeAllElements();
    }
    protected synchronized void setChanged() {
        changed = true;
    }
    protected synchronized void clearChanged() {
        changed = false;
    }
    public synchronized boolean hasChanged() {
        return changed;
    }
    public synchronized int countObservers() {
        return obs.size();
    }
}
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

# (五)总结

观察者模式在不同的场景下还有不同的叫法,比如在本文的例子中,观察者模式叫做发布-订阅(publish-Subscribe)模式会更合适;观察者模式还可以叫做源-监听器(Source-Listener)模式,但是不管怎么叫,它的定义都是相同的。

上次更新: 2025/02/18, 11:30:08
快速理解装饰者模式,及其在JDK源码中的应用

← 快速理解装饰者模式,及其在JDK源码中的应用

最近更新
01
AI大模型部署指南
02-18
02
半个月了,DeepSeek为什么还是服务不可用
02-13
03
Python3.9及3.10安装文档
01-23
更多文章>
Theme by Vdoing | Copyright © 2023-2025 备案图标 浙公网安备33021202002405 | 浙ICP备2023040452号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式