观察者模式
Rxjava中运用到了观察者模式,那什么是观察者模式呢,现在来学习一下。正所谓观察,就是看,细察事物的现象、动向。在这里看来就是监视目标的动作,然后自己作出相应的回应。
先写一个简单的观察者
-
不可能只有一个观察者是吧,抽象一个观察者接口:
public interface ObserverInterface { //观察者获取到情报要更新状态 public void update(String context); }
-
定义一个观察者类:
public class RealObserver implements ObserverInterface { @Override public void update(String context) { System.out.println("观察到对方动作,开始汇报"); this.reportToBoss(context); System.out.println("汇报完毕"); } //获取到情报要汇报 public void reportToBoss(String context){ System.out.println("老板,有情况。。。目标在" + context); } }
再写一个被观察者
-
抽象一些被观察者的行为。
public interface ObservableInterface { //被观察者的动作 public void eat(); public void sleep(); }
-
定义一个被观察者类:
public class RealObservable implements ObservableInterface { private boolean isEat = false; private boolean isSleep = false; public boolean isEat() { return isEat; } public void setEat(boolean isEat) { this.isEat = isEat; } public boolean isSleep() { return isSleep; } public void setSleep(boolean isSleep) { this.isSleep = isSleep; } @Override public void eat() { System.out.println("我吃饭了。。。"); this.isEat = true; } @Override public void sleep() { System.out.println("我睡觉了。。。"); this.isSleep = true; } }
其中就是对两个布尔值的操作,同时还有get/set方法以便获取当前值并进行修改。
写一个线程类
既然要观察监视,就要时刻关注被观察者的状态,以便能在其发生改变的时候及时的更新自己的状态,那么我们就开一条子线程一直在其中循环判断嘛,这不就行了么。
public class WatchThread extends Thread {
// 被观察者
private RealObservable mRealObservable;
// 观察者
private RealObserver mReObserver;
// 具体的监视事件
private String mType;
WatchThread(RealObservable realObservable ,RealObserver realObserver ,String type){
this.mRealObservable = realObservable;
this.mReObserver = realObserver;
this.mType = type;
}
@Override
public void run() {
while (true) {
if (this.mType.equals("eat")) {
if (this.mRealObservable.isEat()){
this.mReObserver.update("吃饭。。。");
//重置状态,以便继续继续监视更新状态
this.mRealObservable.setEat(false);
}
} else {
if (this.mRealObservable.isSleep()){
this.mReObserver.update("睡觉了。。。");
//重置状态,以便继续继续监视更新状态
this.mRealObservable.setSleep(false);
}
}
}
}
}
开启线程
那么现在,万事俱备,只欠东风。在主线程中,创建子线程,并开启线程,获取打印结果。
public static void main(String[] args) throws InterruptedException {
//定义出观察者和被观察者
RealObservable realObservable = new RealObservable();
RealObserver realObserver= new RealObserver();
//创建监视吃饭线程,并开启
WatchThread eatWatch = new WatchThread(realObservable, realObserver, "eat");
eatWatch.start();
//创建监视睡觉线程,并开启
WatchThread sleepWatch = new WatchThread(realObservable, realObserver, "sleep");
sleepWatch.start();
//主线程休眠1.5s,确保子线程开启完成
Thread.sleep(1500);
//改变被观察者状态
realObservable.eat();
Thread.sleep(1000);
realObservable.sleep();
}
打印结果:</br>
我吃饭了。。。</br>
观察到对方动作,开始汇报</br>
老板,有情况。。。目标在吃饭。。。</br>
汇报完毕</br>
我睡觉了。。。</br>
观察到对方动作,开始汇报</br>
老板,有情况。。。目标在睡觉了。。。</br>
汇报完毕</br>
观察者的另一层含义
那么,这样并不算完,注意到没有,我们在子线程开一个无限死循环while(true)作监听,这样的成本太高。那应该如何进行修改呢,这里换一个方向想,我们需要的是什么,我们需要的是如果被观察者的状态发生了改变,或者说触发了什么事件,我们能够及时的获得这个情报,我们也只需要这个情报,想想看过的谍战片,一直派人监视目标是不是很累,并且需要大量的资源,就像这里的while(true)死循环一样,而有的人就买通目标身边的亲信,让亲信给自己送情报,一旦目标有什么动作就通知自己,这样是不是降低了很多成本,当然买通亲信也是要成本的咯。这也就成了观察者另外一层含义,古往今来从来不缺这类人,他有一个时髦的名称:间谍</br>
说了这么多,在代码中如何实现呢,让被观察者持有观察者的对象,在被观察者产生动作后,直接调用观察者的方法,就达到了汇报的目的了。
改进被观察者
-
让被观察者持有观察者对象,并在恰当的时机调用其方法。
public class RealObservable implements ObservableInterface { //创建观察者对象 private ObserverInterface mObserver = new RealObserver(); @Override public void eat() { System.out.println("我吃饭了。。。"); this.mObserver.update("吃饭了"); } @Override public void sleep() { System.out.println("我睡觉了。。。"); this.mObserver.update("睡觉了"); } }
修改主函数
public static void main(String[] args) throws InterruptedException {
//创建被观察者
RealObservable realObservable = new RealObservable();
realObservable.eat();
realObservable.sleep();
}
运行打印结果:</br>
我吃饭了。。。</br>
观察到对方动作,开始汇报</br>
老板,有情况。。。目标在吃饭了</br>
汇报完毕</br>
我睡觉了。。。</br>
观察到对方动作,开始汇报</br>
老板,有情况。。。目标在睡觉了</br>
汇报完毕</br>
打印结果正确,同时效率也提高了。那么是不是这样就够了呢,想一想,我们难道只有一个观察者么,
被观察者的行为难道仅仅是“吃饭”,“睡觉”么,我们应该要达到想增加观察者或者删除观察者,一行代码就搞定的目的,这样的代码才方便后期的拓展和维护是吧。
改进被观察者接口
-
我们要控制对观察者的增加和删除,也就是要求在被观察者类中进行操作,那么抽象一个接口,里面定义增加观察者和删除观察者的方法。
public interface ObservableInterface { //添加观察者 public void addObserver(ObserverInterface observer); //移除观察者 public void removeObserver(ObserverInterface observer); //通知观察者 public void notifyObserver(String context); }
-
重新定义被观察者类:
public class RealObservable implements ObservableInterface { private List<ObserverInterface> mObserverList = new ArrayList<ObserverInterface>(); @Override public void addObserver(ObserverInterface observer) { mObserverList.add(observer); } @Override public void removeObserver(ObserverInterface observer) { mObserverList.remove(observer); } @Override public void notifyObserver(String context) { for (ObserverInterface observer : mObserverList) { observer.update(context); } } public void eat(){ System.out.println("我吃饭了。。。"); this.notifyObserver("吃饭了"); } public void sleep(){ System.out.println("我睡觉了。。。"); this.notifyObserver("睡觉了"); } }
-
为了让结果更直观,对观察者也作出适当的修改:
public class RealObserver implements ObserverInterface { private String name = null; public RealObserver(String name){ this.name = name; } @Override public void update(String context) { System.out.println("我是" + name + "观察到对方动作,开始汇报"); this.reportToBoss(context); System.out.println("汇报完毕"); } //获取到情报要汇报 public void reportToBoss(String context){ System.out.println("老板,有情况。。。目标在" + context); } }
-
运行主函数:
public static void main(String[] args) throws InterruptedException { //创建被观察者 RealObservable Observable = new RealObservable(); //创建观察者 ObserverInterface zhangsan = new RealObserver("zhangsan"); ObserverInterface lisi = new RealObserver("lisi"); ObserverInterface wangwu = new RealObserver("wangwu"); //加入观察者集合 Observable.addObserver(zhangsan); Observable.addObserver(lisi); Observable.addObserver(wangwu); //被观察者发生动作 Observable.eat(); }
打印结果:</br>
我吃饭了。。。</br>
我是zhangsan观察到对方动作,开始汇报</br>
老板,有情况。。。目标在吃饭了</br>
汇报完毕</br>
我是lisi观察到对方动作,开始汇报</br>
老板,有情况。。。目标在吃饭了</br>
汇报完毕</br>
我是wangwu观察到对方动作,开始汇报</br>
老板,有情况。。。目标在吃饭了</br>
汇报完毕</br>
现在基本上是算完成了,说了这么多,其实JDK中给我们提供了观察者和被观察者(Observer/Observable),当中的方法也和我们所说的差不多,不过看源码可以看出,JDK中的被观察者是使用线程安全的Vector保存观察者对象。
附上使用代码:
-
观察者
public class RealObserver implements Observer{
private String name = null;public RealObserver(String name){ this.name = name; } @Override public void update(Observable o, Object arg) { System.out.println("我是" + name + "观察到对方动作,开始汇报"); this.reportToBoss(arg.toString()); System.out.println("汇报完毕"); } //获取到情报要汇报 public void reportToBoss(String context){ System.out.println("老板,有情况。。。目标在" + context); }
}
-
被观察者
public class RealObservable extends Observable { public void eat(){ System.out.println("我吃饭了"); super.setChanged(); super.notifyObservers("吃饭"); } public void sleep(){ System.out.println("我睡觉了"); super.setChanged(); this.notifyObservers("睡觉"); } }
-
主函数
public class OberserDemo { public static void main(String[] args) { //创建被观察者 RealObservable ob = new RealObservable(); //创建观察者 Observer zhangsan = new RealObserver("zhangsan"); Observer lisi = new RealObserver("lisi"); Observer wangwu = new RealObserver("wangwu"); //添加进观察者集合 ob.addObserver(zhangsan); ob.addObserver(lisi); ob.addObserver(wangwu); //被观察者发生动作 ob.eat(); } }
打印结果:</br>
我吃饭了</br>
我是wangwu观察到对方动作,开始汇报</br>
老板,有情况。。。目标在吃饭</br>
汇报完毕</br>
我是lisi观察到对方动作,开始汇报</br>
老板,有情况。。。目标在吃饭</br>
汇报完毕</br>
我是zhangsan观察到对方动作,开始汇报</br>
老板,有情况。。。目标在吃饭</br>
汇报完毕</br>