深入理解观察者模式

观察者模式是用于解耦的,把不同功能的类,而又对某一共同事件或者消息感兴趣解耦开来,使双方互不知道对方。常规的实现是通过接口的方式来把需要关注的消息封装起来,双方各自实现接口即可。

理解观察者模式

什么是观察者模式

观察者模式Observer pattern用于解耦消息发布或者状态发布的,对象之间有消息依赖的一种设计模式。消息发布者,或者说被关注者称之为主体(Subject),它会不定时的更新消息和状态,希望接收到消息和状态变化的称为观察者(Observer)。用接口来隔离主题对象(被关注者)和观察者,观察者被动接收来自主题的变化,然后更新自己的状态。

通常也被称作为发布-订阅者模式因为它与生活中的报纸杂志订阅非常的类似,用户(Subscriber)向发行商(Publisher)订阅,当有新的期刊来了时,发行商会邮寄给用户。发行商称之为Subject或者Publisher,用户称之为Observer或者Subscriber,添加订阅称作Subscription,邮寄新期刊称之为notify。

Subject持有一个Observer的列表,提供三个接口:添加订阅(attach或者addObserver),取消订阅detach或者removeObserver)和通知更新(notify),Observer则有一个更新(update)。

订阅 关系建立后,当有新的数据或者状态需要更新时,Subject就会调用notify接口来实现状态的发布。

观察者模式的示例

对于大部分编程语言来说都提供了观察者模式的接口,比如Java中就可以直接用java.util.Observable和java.util.Observer来实现。

java 复制代码
import java.util.Observable;
import java.util.Observer;
import java.util.Random;

public class TestDriver {
    public static void main(String[] args) {
        final MusicTeacher teacher = new MusicTeacher();
        final Student tommy = new Student("Tommy", findViewById(R.id.tommy));
        final Student jimmy = new Student("Jimmy", findViewById(R.id.jimmy));
        final Student george = new Student("George", findViewById(R.id.george));
        teacher.addObserver(tommy);
        teacher.addObserver(jimmy);
        teacher.addObserver(george);

        teacher.singWithMe();
        teacher.singWithMe();
        teacher.singWithMe();
    }
}

class MusicTeacher extends Observable {
    private static final String[] songs = {
            "\tTwinkle twinkle little star,\n\tHow I wonder what you are.",
            "\tJohnny Johnny?\n\tYes papa.\n\tEating sugar?\n\tNo papa.",
            "\tHumpty dumpty sat on wall,\n\tHumpty dumpty had a great fall.",
            "\tOne two three four five,\n\tOnce I caught a fish alive."
    };
    private Random random;

    public MusicTeacher() {
        random = new Random(System.currentTimeMillis());
    }

    public void singWithMe() {
        setChanged();
        notifyObservers(songs[random.nextInt(songs.length)]);
    }
}

class Student implements Observer {
    private final String name;

    public Student(String name) {
        this.name = name;
    }

    @Override
    public void update(Observable observable, Object o) {
        System.out.println(name + ":\n" + o.toString());
    }
}

常规的实现是这样的,在代码层面有直接的依赖,也就是说Observable与Observer相互知道对方的存在,且代码上面有直接的编译依赖关系。并且一般也都是同步的,状态变化 后Subject会直接发出通知,以更新Observer。

什么时候用观察者模式

观察者模式的特点是『一对多』,主体只有一个,向多个观察者发布状态更新,这是它最主要的特点。另外就是,它最主要的作用是解耦 这种『一对多』状态更新关系。所以,当需要解决这种『一对多』状态更新的问题时就可以使用观察者模式。

厘清问题,找到主体Subject,再找到Observer,然后分别实现对应的接口即可。

发布-订阅模式

随着软件越来越复杂,比如组件的出现,多中间件的出现,远程(服务器客户端),并发和多线程多进程的出现,使得观察者模式也有了新的样式,比如Subject和Observer可以不会有直接依赖关系,或者都依赖于一个中间组件,比如一些Event-Bus系统,以及消息的更新与通知都是异步的。 这时就是出现了发布-订阅者模式(Publish-Subscrib pattern)。 向外发布消息的叫Publisher,它与Observable类似,但最重要的区别在于,Publisher并不知道Subscriber的存在,它是直接像一个第三方的消息队列,或者叫做消息平台,发布消息。而Subscriber,也不知道Publisher的存在,是直接向消息队列或者消息平台订阅。

它的特点是:

  • 组件间,甚至是不同的应用之间,不同的端之间的消息发布模型。
  • 都是异步的,就说是发布者是往消息队列发消息,然后就算发布完成了。订阅者是从消息队列拿消息。Publisher与Subscriber之间并无同步关系。一个消息发布出去,接收时间不确定。
  • 对应该关系自由,可以多对多,也可以多对一或者一对多。
  • 支持并发。

安卓里面非常著名的EventBus就是这一模式的经典实现。以及Linux世界里的dbus也是这种。

关于观察者模式与发布者模式区别可以看这篇文章

生产者消费者问题

再有一个比较类似的就是生产者和消费者问题(Producer consumer problem)主要是涉及多线程和同步问题。

参考资料

欢迎搜索并关注 公众号「稀有猿诉」 获取更多的优质文章!

保护原创,请勿转载!

相关推荐
Kapaseker3 小时前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴3 小时前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭13 小时前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab14 小时前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
BoomHe19 小时前
Now in Android 架构模式全面分析
android·android jetpack
二流小码农1 天前
鸿蒙开发:上传一张参考图片便可实现页面功能
android·ios·harmonyos
鹏程十八少1 天前
4.Android 30分钟手写一个简单版shadow, 从零理解shadow插件化零反射插件化原理
android·前端·面试
Kapaseker1 天前
一杯美式搞定 Kotlin 空安全
android·kotlin
三少爷的鞋1 天前
Android 协程时代,Handler 应该退休了吗?
android
火柴就是我2 天前
让我们实现一个更好看的内部阴影按钮
android·flutter