今天星期五了(异常的兴奋,周末又可以去**了,提前祝大家周末愉快),完成项目经理的需求之后开始继续最近几期博客的编写。承接上一篇博客单例模式,这一期我们一起来了解一下观察者模式。我们最近几期博客打算主要讲一下单例模式、观察者模式、Build模式,目的是为了方便后期为大家带来RXJava+Retrofit2.0+Okhttp3结合使用的网络请求框架。
周末两天过的真快,不过我一直在想我怎么才能写的简单明了,写出观察者模式的精华。
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
一个被观察者对象(ConcreteObservable也被叫为具体的主题ConcreteSubject)可以有一个或多个观察者(Observer)。观察者(这里说的就是具体观察者ConcreteObserver)可以是实现了 观察者(Observer) 接口的任意对象。一个 observable 实例改变后,调用 观察者(observable) 的notifyObservers()方法的应用程序会通过调用观察者的update() 方法来通知观察者该实例发生了改变。
是不是感觉有点没理过来,很混乱。其实简单理解观察者模式就是:1个抽象的被观察者(java中的一个类Observable)和多个抽象的观察者(java中的一个接口Observer)两者之间的订阅——发布的关系;抽象的东西只是概念,所以我们要具体化,具体到我们的项目中的对象;就有了具体主题(ConcreteSubject 继承了观察者{Observable}类)和具体的观察者(ConcreteObserver实现了观察者{Observer}接口)。
如果这样还是不好理解,我们就来个具体的例子,比如我们现在的微信公众号(把它认为是具体的主题继承了被观察者对象)以及很多微信用户(把它认为是具体的观察者实现 了观察者接口);我们用户只要订阅了某微信公众号,那么只要微信公众号发布信息,我们用户就会收到消息并调用更新方法(update())。这样一个关系叫观察者模式(更喜欢叫它为订阅——发布的模式)。
观察者方法说明:
update(Observable o,Object arg)
只要改变了 observable 对象就调用此方法。
被观察者方法说明:
notifyObservers(Object arg)
通知其所有观察者,内容发生变化。
addObserver(Observer o)
如果观察者与集合中已有的观察者不同,则向对象的观察者集中添加此观察者。
deleteObserver(Observer o)
从对象的观察者集合中删除某个观察者。
角色介绍:
思前想后,我到底要做个什么例子啦,微信公众号——微信用户的(发布与订阅关系),确实比较贴近生活;但是好像这个例子有点烂大街了。我就做个项目经理(被观察者)——技术部员工(一群观察者,当然你说可不可只有一个技术人员了也可以的,全栈)这个例子吧;这个也挺好理解的吧,你被录用分配到技术部,不管你负责前端、后端、后台、数据库、还是美工;这样你们就要听项目经理的安排(订阅了),经理今天发布通知:必须在周5完成这个项目上线(发布)。是不是大家都受到消息开始干自己的事情,知道有一天前端干不下去了,离职了,是不是就解除这个订阅关系,不再受到通知。那么让我们一起来看代码:
import java.util.Observable;
import java.util.Observer;
/**
* 员工观察者角色
*/
public class StaffObserver implements Observer {
private String staff;
private String leader;
LeaderSubject leaderSubject = new LeaderSubject("项目经理");
public StaffObserver(String s) {
staff = s;
}
@Override
public void update(Observable observable, Object o) {
System.out.println(staff+"接受到"+leader+"发送通知:"+o);
}
public void update(String str,Object o){
leader = str;
update(leaderSubject,o);
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
/**
* 领导主题角色继承被观察者
*/
public class LeaderSubject extends Observable {
private List mList;
private String leader;
public LeaderSubject(String s) {
leader = s;
this.mList = new ArrayList();
}
/**
*
* @param o 删除具体观察者
*/
public synchronized void deleteObserver(StaffObserver o) {
super.deleteObserver(o);
if(mList != null && mList.size()>0){
mList.remove(o);
}
}
/**
*
* @param o 增加具体观察者
*/
public synchronized void addObserver(StaffObserver o) {
super.addObserver(o);
if(mList !=null){
mList.add(o);
}
}
/**
* 当调用setChanged(String msg)调用具体实现
* @param msg
*/
@Override
public void notifyObservers(Object msg) {
super.notifyObservers(msg);
if(mList != null){
for (StaffObserver s:mList) {
s.update(leader,msg);
}
}
}
/**
* 被观察者内容发生改变
* @param msg 改变的内容
*/
public void setChanged(String msg) {
//消息更新,通知所有观察者
notifyObservers(msg);
}
}
public class TestObserver {
public static void main(String[] args) {
LeaderSubject leaderSubject = new LeaderSubject("项目经理");
StaffObserver frontEnd = new StaffObserver("FrontEnd");
StaffObserver Database = new StaffObserver("Database");
StaffObserver UI = new StaffObserver("UI");
leaderSubject.addObserver(frontEnd);
leaderSubject.addObserver(Database);
leaderSubject.addObserver(UI);
leaderSubject.setChanged("这周我们完成这个项目,并上线!");
leaderSubject.deleteObserver(UI);
System.out.println("------------------观察者减少");
leaderSubject.setChanged("由于美工的离职,我们延迟上线!");
}
}
是不是很简单,就1个具体观察者类和1个具体被观察这类,然后就是具体的实现类;员工的增加与减少不影响其他员工接受通知。在这个过程中整个流程都是依赖Observer和Observable这些抽象接口和类,所以StaffObserver和LeaderSubject完全没有耦合,保证了整个系统的灵活性和可拓展性。
这就达到了我们解耦的效果了,观察者模式。
优点:
观察者和被观察者没有耦合,增强了系统灵活性和可拓展性。
缺点:
被观察者是按顺序执行,如果业务负责,被观察者很多,那么就会影响效率;同时如果其中一个卡顿会影响后面的观察者,所以我们建议这种情况使用异步任务。
现在其实有很多观察者模式的具体实现:比如我们的Android源码BaseAdapter,开源框架EventBus,以及RxJava等等。
如果想看的人多,我们会在这篇博客下继续更新EventBus和Rxjava的简单讲解以及源码分析。