观察者模式

概述

组成

​ 主题+订阅者(观察者)=观察者模式
​ 主题“接口”(自定义或者Observable类):remove(Object o);add(Object o);notify();
​ 订阅者”接口“(自定义或者Observer接口):update();api

定义

图片描述
​ 观察者模式:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它全部的依赖者都会收到通知并自动更新。但注意的是,这种一对多的关系并非绝对的,一个观察者一样能够观察多个主题。数组

设计原则

为了交互对象之间的松耦合而努力。松耦合的设计之因此能让咱们创建有弹性的OO系统,可以够应对变化,是由于对象之间的互相依赖降到了最低。函数

松耦合:两个对象松耦合,它们依然能够交互,可是不清楚彼此的细节。this

观察者模式提供了一种对象设计,让主题和观察者之间松耦合:关于观察者的一切,主题只知道观察者实现了某个接口(也就是Observer接口)。主题不须要知道观察者的具体类型是哪一种、作了些什么或其余任何细节。spa

实现

​ 实现观察者模式的方式不止一种,但其中以包含Subject和Observer接口的类设计最为常见。设计

​ 注意:在例子中还提供了主题是基类观察者是接口的实例,不推荐的主要缘由是继承类只能继承一个这里继承了就没法继承其余的。server

​ 观察者模式有主题推送观察者获取两种类型:对象

订阅/取消功能

​ 不管是对于主题推送类型仍是观察者获取类型,都有一个这样的功能的实现:订阅者进行订阅和取消订阅为何都是要由订阅者来作,这就是上面的松耦合的设计原则,主题不须要知道订阅者的状态,只须要知道它实现了订阅者接口。为了实现这个功能,首先须要在主题的接口或者基类中中定义相应的public的订阅和取消订阅的方法,好比api中Observable类所实现的:继承

` 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 synchronized void deleteObservers() {
​ obs.removeAllElements();
​ }`

​ 上面的这些方法已经可以让订阅者实现自行订阅的不一样主题功能(当订阅者只订阅一个主题时,订阅能够放在构造函数中来实现),除此以外,若是想要订阅者可以取消订阅,还须要在订阅者对象中保留相应主题对象的引用(在api中Observer是一个接口),当要取消订阅的时候直接经过主题引用调用deleteObserver(this)方法便可。这样就可以实现订阅者本身来进行订阅主题和取消订阅主题。当一个订阅者订阅多个具体主题实现对象的时候,能够考虑使用容器来进行管理,在取消订阅的时候也可能够遍历容器找到相应的Class类型的主题对象或者找到相同的的主题对象,而后再地调用deleteObserver(this)便可。

​ api中订阅者和主题二者接口/基类中的成员,以下图所示,在主题基类中能够看到除了咱们上面说的:通知、添加订阅者、删除订阅者这些方法以外,还有一系列关于changed成员变量的方法,为何要引入这个布尔变量呢?缘由参考Why do I need to call setChanged before I notify the observers?

图片描述

主题推送类型

​ 主题推送在自定义的的时候就是经过notify()在内部遍历订阅者数组将所有参数通通发给全部订阅者,在这里由于不一样订阅者所需的参数不一样,因此必须将全部参数都传递过去。订阅者中设置了与要接受的某些参数对应类型的成员变量。(实例可参考)
​ 主题推送在基于api实现的时候就是当参数改变时经过调用notifyObservers(Object arg)将参数放在arg里。在这里由于不一样订阅者所需的参数不一样,因此必须将全部参数都传递过去。而后订阅者在重写的update(Observable o, Object arg)里去取就行,其余的和自定义基本相同。其中第一个Object o是将主题的引用传递过去了,这是为了让观察者可以知道是哪一个主题的通知它的。由于一个观察者能够观察多个主题。

观察者获取类型

​ 观察者获取在自定义的时候就是在主题的具体实现里添加上全部数据的get方法(由于数据都是私有的),而后在订阅者在重写的当中update(Object o);其中o是将主题的引用传递过去,经过主题引用来调用get方法获取所想要的参数(不必定是所有了)。固然也能够不这样实现update,直接只是update(),可是须要在订阅者对象中设置有主题对象的引用,一样是根据引用调用get方法获取参数,但这样的作法缺点在于不利于应对一个订阅者订阅多个主题对象的状况。

​ 观察者获取在基于api实现的时候就是当参数改变时经过调用notifyObservers()从而会调用notifyObservers(null),而后调用订阅者重写的update(Observable o, null)方法里来进一步经过主题的引用来调用get方法获取所想要的参数(不必定是所有了)(实例可参考)。其中第一个Object o是将主题的引用传递过去了,这是为了让观察者可以知道是哪一个主题的通知它的。由于一个观察者能够观察多个主题。

基于API实现的缺点

​ 基于api实现主题有个显著的缺点,由于Observable是一个类,而不是接口,若是继承了Observable类,那就没法继承其余类了。若是必需要继承其余类,那仍是须要自行来实现主题接口和主题的具体实现类

优势

​ 任什么时候候咱们均可以随时增长观察者,由于主题惟一依赖的东西是一个实现Observer接口的对象列表,因此咱们能够随时增长观察者。事实上,在运行时咱们能够用新的观察者取代旧的观察者,主题不会受到影响。一样,也能够在任什么时候候删除观察者。

​ 有新类型的观察者出现时,主题的代码不须要修改。假如咱们有个新的具体类须要当观察者,咱们不须要为了兼容新类型而修改主题的代码,所要作的是在新的类里实现此观察者接口,而后注册为观察者便可。

​ 改变主题或观察者其中一方,并不会影响另外一方。由于二者是松耦合的,因此只要他们之间的接口仍被遵照,咱们就能够自由地改变他们。

相关文章
相关标签/搜索