深入理解观察者模式

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

理解观察者模式

什么是观察者模式

观察者模式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)主要是涉及多线程和同步问题。

参考资料

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

保护原创,请勿转载!

相关推荐
沐怡旸6 分钟前
【底层机制】Android内存管理技术深度解析:PMEM、ION与DMA-BUF Heaps
android·面试
帅锅锅00716 分钟前
process 类权限详解
android·操作系统
2501_9400940234 分钟前
CHDroid 安卓上的游戏ROM CHD格式转换工具软件 游戏ROM容量压缩
android·游戏
猪哥帅过吴彦祖1 小时前
Flutter 从入门到精通:状态管理入门 - setState 的局限性与 Provider 的优雅之道
android·flutter·ios
用户69371750013841 小时前
Kotlin 协程 快速入门
android·后端·kotlin
金鸿客1 小时前
用Compose实现一个Banner轮播组件
android
狂团商城小师妹1 小时前
JAVA国际版同城服务同城信息同城任务发布平台APP源码Android + IOS
android·java·ios
老华带你飞2 小时前
记录生活系统|记录美好|健康管理|基于java+Android+微信小程序的记录生活系统设计与实现(源码+数据库+文档)
android·java·数据库·vue.js·生活·毕设·记录生活系统
峥嵘life2 小时前
Android16 更新fastboot版本解决fastbootd模式识别不到设备问题
android·学习
puyaCheer3 小时前
Android 打开 在线 pdf 文件
android·pdf