设计模式 观察者模式 以微信公众服务为例
继续设计模式的文章,今天给大家带来观察者模式。
先来看看观察者模式的定义:
定义了对象之间的一对多的依赖。这样一来,当一个对象改变时。它的全部的依赖者都会收到通知并自己主动更新。
好了。对于定义的理解总是须要实例来解析的,如今的微信服务号相当火啊,以下就以微信服务号为背景。给大家介绍观察者模式。
看一张图:
当中每一个使用者都有上图中的3条线,为了使图片清晰省略了。
如上图所看到的。服务号就是我们的主题,使用者就是观察者。如今我们明白下功能:
1、服务号就是主题。业务就是推送消息
2、观察者仅仅须要订阅主题。仅仅要有新的消息就会送来
3、当不想要此主题消息时,取消订阅
4、仅仅要服务号还在。就会一直有人订阅
好了。如今我们来看看观察者模式的类图:
接下来就是代码时间了,我们模拟一个微信3D彩票服务号。和一些订阅者。
首先開始写我们的主题接口。和观察者接口:
package com.zhy.pattern.observer; /** * 主题接口,全部的主题必须实现此接口 * * @author zhy * */ public interface Subject { /** * 注冊一个观察着 * * @param observer */ public void registerObserver(Observer observer); /** * 移除一个观察者 * * @param observer */ public void removeObserver(Observer observer); /** * 通知全部的观察着 */ public void notifyObservers(); }
package com.zhy.pattern.observer; /** * @author zhy 全部的观察者须要实现此接口 */ public interface Observer { public void update(String msg); }
接下来3D服务号的实现类:
package com.zhy.pattern.observer; import java.util.ArrayList; import java.util.List; public class ObjectFor3D implements Subject { private List<Observer> observers = new ArrayList<Observer>(); /** * 3D彩票的号码 */ private String msg; @Override public void registerObserver(Observer observer) { observers.add(observer); } @Override public void removeObserver(Observer observer) { int index = observers.indexOf(observer); if (index >= 0) { observers.remove(index); } } @Override public void notifyObservers() { for (Observer observer : observers) { observer.update(msg); } } /** * 主题更新消息 * * @param msg */ public void setMsg(String msg) { this.msg = msg; notifyObservers(); } }
模拟两个使用者:
package com.zhy.pattern.observer; public class Observer1 implements Observer { private Subject subject; public Observer1(Subject subject) { this.subject = subject; subject.registerObserver(this); } @Override public void update(String msg) { System.out.println("observer1 得到 3D 号码 -->" + msg + ", 我要记下来。"); } }
package com.zhy.pattern.observer; public class Observer2 implements Observer { private Subject subject ; public Observer2(Subject subject) { this.subject = subject ; subject.registerObserver(this); } @Override public void update(String msg) { System.out.println("observer2 得到 3D 号码 -->" + msg + "我要告诉舍友们。"); } }能够看出:服务号中维护了全部向它订阅消息的使用者,当服务号有新消息时,通知全部的使用者。
整个架构是一种松耦合,主题的实现不依赖与使用者。当添加新的使用者时,主题的代码不须要改变;使用者怎样处理得到的数据与主题无关。
最后看下測试代码:
package com.zhy.pattern.observer.test; import com.zhy.pattern.observer.ObjectFor3D; import com.zhy.pattern.observer.Observer; import com.zhy.pattern.observer.Observer1; import com.zhy.pattern.observer.Observer2; import com.zhy.pattern.observer.Subject; public class Test { public static void main(String[] args) { //模拟一个3D的服务号 ObjectFor3D subjectFor3d = new ObjectFor3D(); //客户1 Observer observer1 = new Observer1(subjectFor3d); Observer observer2 = new Observer2(subjectFor3d); subjectFor3d.setMsg("20140420的3D号码是:127" ); subjectFor3d.setMsg("20140421的3D号码是:333" ); } }
输出结果:
observer1 得到 3D 号码 -->20140420的3D号码是:127, 我要记下来。 observer2 得到 3D 号码 -->20140420的3D号码是:127我要告诉舍友们。 observer1 得到 3D 号码 -->20140421的3D号码是:333, 我要记下来。observer2 得到 3D 号码 -->20140421的3D号码是:333我要告诉舍友们。
对于JDK或者Andorid中都有非常多地方实现了观察者模式,比方XXXView.addXXXListenter , 当然了 XXXView.setOnXXXListener不一定是观察者模式,由于观察者模式是一种一对多的关系,对于setXXXListener是1对1的关系,应该叫回调。
恭喜你学会了观察者模式,上面的观察者模式使我们从无到有的写出,当然了java中已经帮我们实现了观察者模式,借助于java.util.Observable和java.util.Observer。
以下我们使用Java内置的类实现观察者模式:
首先是一个3D彩票服务号主题:
package com.zhy.pattern.observer.java; import java.util.Observable; public class SubjectFor3d extends Observable { private String msg ; public String getMsg() { return msg; } /** * 主题更新消息 * * @param msg */ public void setMsg(String msg) { this.msg = msg ; setChanged(); notifyObservers(); } }以下是一个双色球的服务号主题:
package com.zhy.pattern.observer.java; import java.util.Observable; public class SubjectForSSQ extends Observable { private String msg ; public String getMsg() { return msg; } /** * 主题更新消息 * * @param msg */ public void setMsg(String msg) { this.msg = msg ; setChanged(); notifyObservers(); } }
最后是我们的使用者:
package com.zhy.pattern.observer.java; import java.util.Observable; import java.util.Observer; public class Observer1 implements Observer { public void registerSubject(Observable observable) { observable.addObserver(this); } @Override public void update(Observable o, Object arg) { if (o instanceof SubjectFor3d) { SubjectFor3d subjectFor3d = (SubjectFor3d) o; System.out.println("subjectFor3d's msg -- >" + subjectFor3d.getMsg()); } if (o instanceof SubjectForSSQ) { SubjectForSSQ subjectForSSQ = (SubjectForSSQ) o; System.out.println("subjectForSSQ's msg -- >" + subjectForSSQ.getMsg()); } } }看一个測试代码:
package com.zhy.pattern.observer.java; public class Test { public static void main(String[] args) { SubjectFor3d subjectFor3d = new SubjectFor3d() ; SubjectForSSQ subjectForSSQ = new SubjectForSSQ() ; Observer1 observer1 = new Observer1(); observer1.registerSubject(subjectFor3d); observer1.registerSubject(subjectForSSQ); subjectFor3d.setMsg("hello 3d'nums : 110 "); subjectForSSQ.setMsg("ssq'nums : 12,13,31,5,4,3 15"); } }
測试结果:
subjectFor3d's msg -- >hello 3d'nums : 110 subjectForSSQ's msg -- >ssq'nums : 12,13,31,5,4,3 15
能够看出,使用Java内置的类实现观察者模式。代码非常简洁,对了addObserver,removeObserver,notifyObservers都已经为我们实现了,全部能够看出Observable(主题)是一个类,而不是一个接口,基本上书上都对于Java的如此设计抱有反面的态度,认为Java内置的观察者模式,违法了面向接口编程这个原则。可是假设转念想一想。的确你拿一个主题在这写观察者模式(我们自己的实现),接口的思想非常好,可是假设如今继续加入非常多个主题。每一个主题的ddObserver,removeObserver,notifyObservers代码基本都是同样的吧。接口是无法实现代码复用的,并且也没有办法使用组合的模式实现这三个方法的复用,所以我认为这里把这三个方法在类中实现是合理的。