目前很火的RxJava其核心就是观察者模式,定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
举个现实中的例子方便大家理解:《每天一杯鲜牛奶》
小区中的住户订奶,他们和奶场签下协议,每天清晨,送奶员就会准时将新鲜的牛奶放在小区的奶箱中。那么,我们这些住户就相当于订阅者(观察者),奶场就是发布者(被观察者),到一定的时间,奶场通知送奶员发货,然后各家各户就自动收到了新鲜的奶了。其实这个协议就是内部的更新接口,奶场只是调用了通知送奶员的方法,然后传参(一杯鲜奶),调用住户的更新接口(奶箱)。
在比如:《作业风云》
老师布置作业,然后全班同学都知道了,老师就是被观察者,学生就是观察者,学生观察老师布置作业的动作,然后自个获取到这个状态就知道布置作业了。
好了,我们来看一下实现:
首先,我们先抽取这个通知的方法,也就是各个观察者实现的方法,具体的通知结果由各个实现者自个处理:
package com.zndroid.dm.ObserverModel.Custom;
/**
* Created by luzhenyu on 2017/9/11.
*/
/**首先呢,我们抽象出观察者(订阅者),观察者起到更新通知的作用*/
public interface Observer {
void update(Object obj);
}
我们搞几个观察者:
package com.zndroid.dm.ObserverModel.Custom.impl;
import com.zndroid.dm.ObserverModel.Custom.Observer;
import com.zndroid.dm.ObserverModel.Custom.Subject;
/**
* Created by luzhenyu on 2017/9/11.
*/
/**具体实现三个观察者 - 1*/
public class Observer1 implements Observer {
@Override
public void update(Object obj) {
System.out.println("Observer1 found " + ((Subject)obj).getName() + " has changed!");
}
}
package com.zndroid.dm.ObserverModel.Custom.impl;
import com.zndroid.dm.ObserverModel.Custom.Observer;
import com.zndroid.dm.ObserverModel.Custom.Subject;
/**
* Created by luzhenyu on 2017/9/11.
*/
/**具体实现三个观察者 - 2*/
public class Observer2 implements Observer {
@Override
public void update(Object obj) {
System.out.println("Observer2 found " + ((Subject)obj).getName() + " has changed!");
}
}
package com.zndroid.dm.ObserverModel.Custom.impl;
import com.zndroid.dm.ObserverModel.Custom.Observer;
import com.zndroid.dm.ObserverModel.Custom.Subject;
/**
* Created by luzhenyu on 2017/9/11.
*/
/**具体实现三个观察者 - 3*/
public class Observer3 implements Observer {
@Override
public void update(Object obj) {
System.out.println("Observer3 found " + ((Subject)obj).getName() + " has changed!");
}
}
下面呢,被观察者的行为有:add观察者,delete观察者,notify观察者;这些都是通用的,我们可以抽象出接口
package com.zndroid.dm.ObserverModel.Custom;
/**
* Created by luzhenyu on 2017/9/11.
*/
/**定义被观察者公用接口*/
public interface IObservable {
void add(Observer observer);
void delete(Observer observer);
void notifications();
}
下面是被观察者实现,其核心就是内部存储观察者列表,然后提供给外部(客户端)通知变化的方法,具体的变化会通知到观察者列表中每一个观察者具体的更新方法:
package com.zndroid.dm.ObserverModel.Custom;
/**
* Created by luzhenyu on 2017/9/11.
*/
import java.util.ArrayList;
import java.util.List;
/**被观察者(发布者)*/
public class Subject implements IObservable {
private List<Observer> list;//订阅者列表
private String name;
public Subject() {
list = new ArrayList<>();
}
@Override
public void add(Observer observer) {
System.out.println("Add a observer " + observer.toString());
list.add(observer);//添加订阅者
}
@Override
public void delete(Observer observer) {
System.out.println("Delete a observer " + observer.toString());
list.remove(observer);
}
@Override
public void notifications() {
for (Observer o : list) {
try {
o.update(this);
} catch (Exception e) {
System.out.println("Error");
}//此部分也是JDK中欠考虑的部分
}
}
//通知订阅者发生变化的方法
public void changed() {
System.out.println("Notify observers I'm changed ");
notifications();//通知所有的订阅者‘我’发生变化了
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
下面看一下使用:
/**
* 观察者模式
* 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
* 其核心就是在抽象的被观察者类中存放观察者们。
*
* 但是如果观察者非常多的话相应的时间也会很长;如果观察者与被观察者有循环依赖的话有可能会造成系统崩溃;
* 观察者并不知道被观察者具体怎么变化的,他们只是知道变化了;如果使用的是Java自带的API,如果其中一个观察者出现更新异常就会影响剩下的观察者。
*
* 现在很火的RxJava、RxAndroid核心就是观察者模式
* 在Java中被观察者继承java.util.Observable,观察者实现java.util.Observer接口就实现了观察者模式。
* */
////////// 以下是手动实现 //////////
//实例化一个被观察者
Subject subject = new Subject();
subject.setName("我是一个小小的被观察者,好害羞啊");
Observer1 observer1 = new Observer1();
Observer2 observer2 = new Observer2();
Observer3 observer3 = new Observer3();
//添加订阅者
subject.add(observer1);
subject.add(observer2);
subject.add(observer3);
//我要变化咯~~
subject.changed();//所有的订阅者都会收到通知
log("--------------------- Im delete a observer --------------------");
//去掉一个订阅者
subject.delete(observer2);
subject.changed();//所有的订阅者都会收到通知
log("----------------我是分割线-----------------");
运行结果:
[ ======================================== ]
Add a observer com.zndroid.dm.ObserverModel.Custom.impl.Observer1@42a57993
Add a observer com.zndroid.dm.ObserverModel.Custom.impl.Observer2@75b84c92
Add a observer com.zndroid.dm.ObserverModel.Custom.impl.Observer3@6bc7c054
Notify observers I'm changed
Observer1 found 我是一个小小的被观察者,好害羞啊 has changed!
Observer2 found 我是一个小小的被观察者,好害羞啊 has changed!
Observer3 found 我是一个小小的被观察者,好害羞啊 has changed!
[ --------------------- Im delete a observer -------------------- ]
Delete a observer com.zndroid.dm.ObserverModel.Custom.impl.Observer2@75b84c92
Notify observers I'm changed
Observer1 found 我是一个小小的被观察者,好害羞啊 has changed!
Observer3 found 我是一个小小的被观察者,好害羞啊 has changed!
[ ----------------我是分割线----------------- ]
[ ======================================== ]
以上是我们手动实现的,在java中JDK已经有相应的实现了,我们来看一下怎么使用:
在Java中被观察者继承java.util.Observable,观察者实现java.util.Observer接口
比较源码会发现,和我们的思想是一致的:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package java.util;
import java.util.Observable;
//观察者接口,每个观察者都必须实现的接口,该接口是在被观察的对象发生变化时做出的相应
public interface Observer {
void update(Observable var1, Object var2);
}
import java.util.Vector;
//被观察者类
public class Observable {
//这是一个改变标识,来标记该被观察者有没有改变
private boolean changed = false;
//持有一个观察者列表
private Vector obs;
public Observable() {
obs = new Vector();
}
//添加观察者,添加时会去重
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);
}
//notifyObservers(Object arg)的重载方法
public void notifyObservers() {
notifyObservers(null);
}
//通知所有观察者,被观察者改变了,你可以执行你的update方法了。
public void notifyObservers(Object arg) {
//一个临时的数组,用于并发访问被观察者时,留住观察者列表的当前状态,这种处理方式其实也算是一种设计模式,即备忘录模式。
Object[] arrLocal;
//注意这个同步块,它表示在获取观察者列表时,该对象是被锁定的
//也就是说,在我获取到观察者列表之前,不允许其他线程改变观察者列表
synchronized (this) {
//如果没变化直接返回
if (!changed)
return;
//这里将当前的观察者列表放入临时数组
arrLocal = obs.toArray();
//将改变标识重新置回未改变
clearChanged();
}
//注意这个for循环没有在同步块,此时已经释放了被观察者的锁,其他线程可以改变观察者列表
//但是这并不影响我们当前进行的操作,因为我们已经将观察者列表复制到临时数组
//在通知时我们只通知数组中的观察者,当前删除和添加观察者,都不会影响我们通知的对象
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
//删除所有观察者
public synchronized void deleteObservers() {
obs.removeAllElements();
}
//标识被观察者被改变过了
protected synchronized void setChanged() {
changed = true;
}
//标识被观察者没改变
protected synchronized void clearChanged() {
changed = false;
}
//返回被观察者是否改变
public synchronized boolean hasChanged() {
return changed;
}
//返回观察者数量
public synchronized int countObservers() {
return obs.size();
}
}
我们尝试使用一下:
package com.zndroid.dm.ObserverModel.Java;
import java.util.Observable;
/**
* Created by luzhenyu on 2017/9/11.
*/
public class TimerOb extends Observable {
private long time;
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public void disPlay() {
setChanged();//Java中必须要先告知状态已改变
notifyObservers();
}
}
package com.zndroid.dm.ObserverModel.Java;
import java.util.Observable;
import java.util.Observer;
/**
* Created by luzhenyu on 2017/9/11.
*/
public class Listener1 implements Observer {
@Override
public void update(Observable observable, Object o) {
System.out.println(((TimerOb)observable).getTime());
}
}
package com.zndroid.dm.ObserverModel.Java;
import java.util.Observable;
import java.util.Observer;
/**
* Created by luzhenyu on 2017/9/11.
*/
public class Listener2 implements Observer {
@Override
public void update(Observable observable, Object o) {
System.out.println(((TimerOb)observable).getTime());
}
}
package com.zndroid.dm.ObserverModel.Java;
import java.util.Observable;
import java.util.Observer;
/**
* Created by luzhenyu on 2017/9/11.
*/
public class Listener3 implements Observer {
@Override
public void update(Observable observable, Object o) {
System.out.println(((TimerOb)observable).getTime());
}
}
使用如下:
////////// 下面来看一下Java中自带的实现 //////////
TimerOb timerOb = new TimerOb();
Listener1 listener1 = new Listener1();
Listener2 listener2 = new Listener2();
Listener3 listener3 = new Listener3();
timerOb.addObserver(listener1);
timerOb.addObserver(listener2);
timerOb.addObserver(listener3);
for (int i=0;i<4;i++) {
try {
Thread.sleep(1000);
timerOb.setTime(System.currentTimeMillis());
timerOb.disPlay();
} catch (InterruptedException e) {
e.printStackTrace();
}
log("_________________");
}
log("----------------我是分割线-----------------");
控制台输出,每隔一秒三个订阅者刷新当前时间:
[ ======================================== ]
1505114397015
1505114397015
1505114397015
[ _________________ ]
1505114398015
1505114398015
1505114398015
[ _________________ ]
1505114399015
1505114399015
1505114399015
[ _________________ ]
1505114400015
1505114400015
1505114400015
[ _________________ ]
[ ----------------我是分割线----------------- ]
[ ======================================== ]
【欢迎上码】
【微信公众号搜索 h2o2s2】