今天面试的时候面试官问我观察者模式是什么。
我说balabla...
“那它和发布订阅的区别是什么?”
“没区别!”
“有区别”,面试官微微一笑。
“...”
面完之后吃饭的时候还在想这两者究竟有什么区别?
观察者模式
观察者模式中有两个对象,分别为被观察者(Subject)和观察者(Observer)。
在观察者模式中要实现的是,每当Subject的状态发生改变,Observer自动地随着发生改变,注意这里的Observer可能是多个对象。
因此在Subject中会存有一张包含所有Observer的表,或者说Subject能够访问到所有依赖于它状态的对象。
每当Subject的被观察的事件触发,它就会依次改变这张表里的所有对象,比如调用它们的某个方法。这就要求所有的Observer要实现某一个共同的接口,以便Subject知道调用何种方法。
上图中当Subject的Event发生后,会自动的调用Observers中每一项的notify()这个方法。
问题来了这和发布订阅有什么区别呢?
发布订阅模式
如果说观察者模式是老板群发“今晚加班!”,那么发布订阅更像是委托人在冒险家工会贴一张悬赏“打败魔王有重赏”的告示。
在发布订阅模式中,发布者(Publisher)状态改变后发布一条消息,订阅者(Subscriber)接收到消息后执行某一程序。这样同样实现了多个对象对某一对象状态的依赖,最大的区别就是在发布订阅模式中,发布者和订阅者是“互相不认识”的,也就是说发布者不会像Subject一样存储依赖于它本身的对象。
就和悬赏令一样,发布者想要讨伐魔王(状态改变),把告示发布在冒险家工会(向消息队列中发布一条消息),合适的冒险家在众多的任务中挑选合适的任务(过滤订阅的消息),去讨伐魔王完成任务。(执行对应的程序)
二者的异同
二者的相同之处都是要实现一些对象对另一个对象状态的依赖,这个被依赖的对象可以是Subject,也可以是Publisher。
二者的区别是
- 发布订阅模式中,发布者和订阅者互相不认识,消息的传递通过一条消息总线。而观察者模式中,Subject会存储一个所有观察它的对象的列表,并且直接调用它们的方法。
- 以上的特性决定了发布订阅模式的耦合程度要低于观察者模式。因为发布者和订阅者无需有任何共同之处,只需要共同访问同一条消息总线即可。 而在观察者模式中,由于需要被观察者Subject调用所有观察者的方法,因此所有的Observer需要实现某一共同的接口,这样就会产生一些耦合。
在实际开发有此类需求时,可能不需要特别严格区分两种模式。但是区分出二者的区别不失为一种对设计模式的思维的锻炼。
参考文章:Observer vs Pub-Sub