一:场景说明
记得上初中时,网络还没有现在这么普及,校门口有个小卖部,我常常到哪里订阅报纸,来关心下“天下大事”(当然不止我一个人订阅啦)
如图订阅报纸流程:
订阅报纸的时候常常遇到几个问题?什么时候出版?出版内容是什么?延迟出版怎么办?谁通知我报纸到了?要我去取报纸?还是会有人送过来?等等
把这样的场景带到我们编程世界里来,我们的解决方案之一就是使用观察者设计模式。
二:观察者模式(Observer),定义对象间的一种一对多的依赖关系。当一个对象的状态或内容发生改变时,所有依赖它的对象都得到通知并被自动更新.
观察者模式的结构说明:
三:代码示例:
其实JDK已经实现的Subject和Observer接口的,我们直接可以使用,下面我会介绍的,这里还是先自己实现下,体会下吧
/** * 观察者接口 * 提供通知更新方法 (可以在这个方法中回调目标对象) * Created by Administrator on 2016/4/22. */public interface Observer { void update(Subject subject);}
package com.dy.observer;import java.util.ArrayList;import java.util.List;/** * 目标对象 ,作为被观察者 * 它知道观察者,并提供注册和删除观察者 * Created by Administrator on 2016/4/22. */public class Subject { private ListobserverList = new ArrayList<>(); /** * 注册观察者 ,报纸订阅者 * @param observer */ public void attach(Observer observer){ observerList.add(observer); } /** * 删除观察者 * @param observer */ public void detach(Observer observer){ observerList.remove(observer); } /** * 通知所有观察者 * 每当报纸被印出来,及时主动通知所有订阅者,好让他们知道 */ protected void notifyObserver(){ for (Observer observer:observerList){ observer.update(this); } }}
package com.dy.observer;/** * 目标对象的继承者 * 负责具体观察者状态 * 当自己状态变化,通知所有观察者 * Created by Administrator on 2016/4/22. */public class NewsPaper extends Subject { private String subjectStatus; /** * 报纸内容 */ private String content; public String getSubjectStatus() { return subjectStatus; } public void setSubjectStatus(String subjectStatus) { this.subjectStatus = subjectStatus; //状态改变,通知所有观察者 this.notifyObserver(); } public String getContent() { return content; } public void setContent(String content) { this.content = content; //内容有了,说明报纸被印刷出来了,通知所有观察者 this.notifyObserver(); }}
package com.dy.observer;/** * 读者,报纸订阅者 * * 观察者实现类 * 实现更新方法,使自身状态和目标状态保持一致 * Created by Administrator on 2016/4/22. */public class Reader implements Observer { private String observerStatus; private String name; public Reader(String name) { this.name = name; } @Override public void update(Subject subject) { //实现更新方法,使自身状态和目标状态保持一致 //采用拉的方式 observerStatus = ((NewsPaper) subject).getSubjectStatus(); System.out.println(name+"收到了报纸,阅读它,内容是:"+((NewsPaper) subject).getContent()); } public String getName() { return name; } public void setName(String name) { this.name = name; }}
package com.dy.observer;/** * Created by Administrator on 2016/4/22. */public class Client { public static void main(String[] args) { //报纸被观察者 NewsPaper newsPager = new NewsPaper(); //报纸订阅者,也就是观察者 Reader reader = new Reader("张三"); Reader reader1 = new Reader("李四"); Reader reader2 = new Reader("王二"); //注册订阅者 newsPager.attach(reader); newsPager.attach(reader1); newsPager.attach(reader2); //印刷出报纸内容 newsPager.setContent("本期内容介绍观察者模式"); }}
客户端测试结果:
张三收到了报纸,阅读它,内容是:本期内容介绍观察者模式李四收到了报纸,阅读它,内容是:本期内容介绍观察者模式王二收到了报纸,阅读它,内容是:本期内容介绍观察者模式Process finished with exit code 0
四:使用jdk实现观察者模式
注意修改对应代码
package com.dy.observer.java;import java.util.Observable;/** * Created by Administrator on 2016/4/22. */public class NewsPaper extends Observable { /** * 报纸内容 */ private String content; public String getContent() { return content; } public void setContent(String content) { this.content = content; //内容有了,说明报纸被印刷出来了,通知所有观察者 //注意JDK的observer模式的时候,下面这句代码不可少 this.setChanged(); //主动通知,这里用推的方式 this.notifyObservers(this.content); //如果用的拉的方式,如下代码示例 //this.notifyObservers(); }}
package com.dy.observer.java;import java.util.Observable;import java.util.Observer;/** * 读者,报纸订阅者 * * 观察者实现类 * 实现更新方法,使自身状态和目标状态保持一致 * Created by Administrator on 2016/4/22. */public class Reader implements Observer { private String name; public Reader(String name) { this.name = name; } @Override public void update(Observable o, Object obj) { System.out.println(name+"收到了报纸,目标推过来的内容是:"+obj); //拉的方式你自己想想就知道了((NewsPaper) obj).getContent()) } public String getName() { return name; } public void setName(String name) { this.name = name; }}
public class Client { public static void main(String[] args) { //报纸被观察者 NewsPaper jdk_subject = new NewsPaper(); //报纸订阅者,也就是观察者 Reader reader = new Reader("张三"); Reader reader1 = new Reader("李四"); Reader reader2 = new Reader("王二"); //注册订阅者 jdk_subject.addObserver(reader); jdk_subject.addObserver(reader1); jdk_subject.addObserver(reader2); //印刷出报纸内容 jdk_subject.setContent("本期内容介绍java JDK实现观察者模式"); }}
王二收到了报纸,目标推过来的内容是:本期内容介绍java JDK实现观察者模式李四收到了报纸,目标推过来的内容是:本期内容介绍java JDK实现观察者模式张三收到了报纸,目标推过来的内容是:本期内容介绍java JDK实现观察者模式Process finished with exit code 0