观察者模式VS发布-订阅模式
Posted dotNET跨平台
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了观察者模式VS发布-订阅模式相关的知识,希望对你有一定的参考价值。
前言
观察者模式的大名,想必各位看官早已有所耳闻。从我们现实生活来说,微信公众号订阅、医院挂号叫号等都属于它的实际应用。在程序世界中,它是一种用于将代码解耦的设计模式,如果你想掌握并理解这种设计模式,今天就和我一起来探究它的奥秘之处吧!
观察者模式
在前文讲述事件机制时,我们其实已经提到了观察者模式。观察者模式事实上实现了一种通讯机制,也就是观察目标对观察者进行通知的机制。在基于低耦合的设计前提下,观察者无需直接调用观察目标的内部方法或属性获取通知,而是使用“订阅”的方式获取通知,大体的流程图如下:
结合实际开发例子来说,在C#中我们只需要定义相应的委托和事件,即可实现观察者模式的使用,详细使用方法可以参考我之前的文章内容:再谈C#中的委托和事件,在此不再赘述。
但在其他语言中,例如Java,本身未提供类似委托或事件的机制进行回调,因此在实现方面会略微繁琐一些,相关类图如下:
在这种实现方式中,我们需要对观察目标,也就是发布主题进行一个抽象,即图中的Subject,用于提供保存观察者的集合(图中的ArrayList),以及对观察者的增加或删除的方法。而在具体主题(图中的ConcreteSubject)中,包含了状态属性,以及状态变化的方法,在自身发生变化时,会调用notifyObserver方法进行通知。
在观察者的实现中,也存在抽象观察者(Observer)和具体观察者(ConcreteObserver)两种角色。前者一般定义一个接口,用于在接收到变化通知时,对自身进行更新。而后者会实现具体的update方法,类似C#中我们订阅事件之后触发的回调方法。
以上就是我们在两种语言中分别实现观察者模式的方式,正如软件工程强调的“没有银弹”的说法,观察者模式虽然解决了很多问题,但也存在部分缺点,主要内容如下:
1、观察者数量很多时,逐个通知会非常耗时。正如我们上述实现,存在一个ArrayList来保存所有的观察者,如果这个ArrayList中的元素足够大,那么在通知时程序的执行效率势必是很低下的。
2、如果观察目标与观察者之间存在循环依赖时,观察者模式会触发双方的循环调用,导致系统崩溃。
3、缺乏相应的机制通知观察者观察目标是如何发生变化的,观察者仅仅是得知观察目标发生了变化。当然这一点也不是绝对的,我们在程序实现时可以通过传递参数或者对象的方式去“告知”观察者,观察目标发生了哪些变化。
我们在讲述观察者模式时,反复提到了“主题”和“订阅”的概念。从概念上理解而言,似乎观察者模式,就是发布-订阅模式,那么两者之间究竟有没有区别呢?我们一起进入下一章节来继续探究。
发布订阅模式
事实上,发布订阅模式,和观察者模式是有区别的。回到我们最开始的例子,微信公众号的订阅,看似是直接关注了公众号,实质上,在关注和推送的两种行为中,都是要通过“微信公众平台”这个第三方来实现的。看到这里,聪明的各位应该可以理解到发布订阅模式的不同之处,没错,发布订阅模式是在观察者模式的基础上,加入了“事件中心”的概念:
通过事件中心,发布者和订阅者进行了进一步的解耦,发布者无需关心订阅者的订阅情况,而是直接发布主题到事件中心即可。而订阅者也无需关心发布者自身的情况,甚至不知道发布者是何人,只需要接收事件中心的通知即可。
发布订阅模式在目前的各种消息中间件中应用非常广泛,如常见的RabbitMQ,kafka等,发布者发布主题,消费者订阅对应的主题对发布的消息进行消费,相信大家对这些概念并不陌生。
小结
至此,我们今天要探究的主题就暂时告一段落。观察者模式与发布订阅模式如此相似,但又有所不同,在我们理清各自的概念和实现方式后,又会发现在我们日常的应用中这两种模式无所不在。
设计模式本身就是一些优秀的前辈在开发过程中对一些最佳实践和方法论做出的沉淀和总结,所以大家在提到这些内容时,不要先入为主的认为这些东西只是停留在概念阶段,无法落地实践。而是需要结合自己的实际工作,仔细思考设计模式该如何应用,如何选择合适的设计模式,解决自己遇到的问题。当然,永远没有最优的方案,滥用设计模式只会大大降低程序的可读性,对后续维护造成困难。活学活用,在这里祝愿大家可以和我一起学习,共同进步和成长,我们下期再见!
以上是关于观察者模式VS发布-订阅模式的主要内容,如果未能解决你的问题,请参考以下文章