观察者模式的定义:
定义了对象之间的一对多的依赖,这样一来,当一个对象改变时,它的所有的依赖者都会收到通知并自动更新。
观察者模式的类图:
根据类图自定义主题、观察者接口:
package observer;/** * 主题接口 * @author 发挥哥 * */public interface Subject { /** * 注册观察者 * @param observer 观察者对象 */ void registerObserver(Observer observer); /** * 移除观察者 * @param observer 观察者对象 */ void removeObserver(Observer observer); /** * 通知所有观察者 */ void notifyObservers();}
package observer;/** * 观察者接口 * @author 发挥哥 * */public interface Observer { /** * 主题通知所有观察者,执行该方法 * @param msg */ void update(String msg);}
创建主题类和观察者类:
package observer;import java.util.ArrayList;import java.util.List;import observer.Subject;/** * 自定义主题类,实现自定义主题接口 * @author 发挥哥 * */public class TestSubject implements Subject { /** * 所有注册到该主题的观察者 */ private Listobservers=new ArrayList<>(); /** * 主题的状态 */ private String msg; @Override public void registerObserver(Observer observer) { // TODO Auto-generated method stub if(observers!=null&&observer!=null) observers.add(observer); } @Override public void removeObserver(Observer observer) { // TODO Auto-generated method stub if(observers.contains(observer)) { observers.remove(observer); } } @Override public void notifyObservers() { // TODO Auto-generated method stub observers.stream().forEach(observer->{ observer.update("主题更新了,大家注意:"+this.msg); }); } /** * 编辑主题的状态后,通知所有观察者 * @param msg */ public void editMsg(String msg) { this.msg = msg; notifyObservers(); }}
package observer;/** * 观察者1 * @author 发挥哥 * */public class Test1Observer implements Observer { /** * 创建观察者对象时,将其注册到指定的主题 * @param subject */ public Test1Observer(Subject subject) { subject.registerObserver(this); } /** * 当主题状态变化时,通过调用该方法通知观察者 */ @Override public void update(String msg) { // TODO Auto-generated method stub System.out.println(this.getClass().getName()+"收到主题发来的消息:"+msg); }}
package observer;/** * 观察者2(仅为测试,实现与观察者1一样) * @author 发挥哥 * */public class Test2Observer implements Observer { public Test2Observer(Subject subject) { subject.registerObserver(this); } @Override public void update(String msg) { // TODO Auto-generated method stub System.out.println(this.getClass().getName()+"收到主题发来的消息:"+msg); }}
创建测试方法:
package observer;public class TestMain { public static void main(String[] args) { //创建主题 TestSubject subject=new TestSubject(); //创建观察者1并注册到主题 Observer observer1=new Test1Observer(subject); //创建观察者2并注册到主题 Observer observer2=new Test2Observer(subject); //主题进行2次状态修改 subject.editMsg("第一次调整!"); subject.editMsg("第二次调整!"); }}
测试结果如下:
observer.Test1Observer收到主题发来的消息:主题更新了,大家注意:第一次调整!
observer.Test2Observer收到主题发来的消息:主题更新了,大家注意:第一次调整! observer.Test1Observer收到主题发来的消息:主题更新了,大家注意:第二次调整! observer.Test2Observer收到主题发来的消息:主题更新了,大家注意:第二次调整!
以上是自定义主题和观察者接口及其实现,JDK中已经帮我们实现了观察者模式,借助于java.util.Observable和java.util.Observer:
package java.util;public class Observable { private boolean changed = false; private Vectorobs; 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); } public void notifyObservers() { notifyObservers(null); } public void notifyObservers(Object arg) { Object[] arrLocal; synchronized (this) { if (!changed) return; arrLocal = obs.toArray(); clearChanged(); } 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 java.util;public interface Observer { void update(Observable o, Object arg);}
类java.util.Observable和接口java.util.Observer比较简单,直接借此创建主题和观察者类:
package observer.jdk;import java.util.Observable;/** * 主题1 * @author 发挥哥 * */public class MySubject extends Observable { private String msg; /** * 编辑主题消息,并将变动标志置true,通知所有观察者,再将标志置false * @param msg */ public void editMsg(String msg) { if(msg==null) { this.msg = msg; setChanged(); notifyObservers("主题将消息置空!"); clearChanged(); return; } if(this.msg!=null&&msg!=null&&this.msg.equals(msg)) { return; } this.msg = msg; setChanged(); notifyObservers("主题更新消息:"+this.msg); clearChanged(); }}
package observer.jdk;import java.util.Observable;/** * 主题2(仅为测试,与观察者1实现一样) * @author 发挥哥 * */public class OtherSubject extends Observable { private String msg; public void editMsg(String msg) { if(msg==null) { this.msg = msg; setChanged(); notifyObservers("主题将消息置空!"); clearChanged(); return; } if(this.msg!=null&&msg!=null&&this.msg.equals(msg)) { return; } this.msg = msg; setChanged(); notifyObservers("主题更新消息:"+this.msg); clearChanged(); }}
package observer.jdk;import java.util.Observable;import java.util.Observer;/** * 观察者 * @author 发挥哥 * */public class MyObserver implements Observer { /** * 通过该方法将观察者自己注册到主题 * @param observable */ public void registerToSubject(Observable observable) { observable.addObserver(this); } @Override public void update(Observable o, Object arg) { System.out.println(this.getClass().getName()+"收到主题"+o.getClass().getName()+"更新消息:"+arg); }}
编写测试方法:
package observer.jdk;public class MyTest { public static void main(String[] args) { //创建主题1、主题2 MySubject subject1=new MySubject(); OtherSubject subject2=new OtherSubject(); //创建观察者 MyObserver observer=new MyObserver(); //将观察者注册到主题1、主题2 observer.registerToSubject(subject1); observer.registerToSubject(subject2); //主题1、主题2分别更新状态 subject1.editMsg("主题一更新"); subject2.editMsg("主题二更新"); }}
测试结果如下:
observer.jdk.MyObserver收到主题observer.jdk.MySubject更新消息:主题更新消息:主题一更新
observer.jdk.MyObserver收到主题observer.jdk.OtherSubject更新消息:主题更新消息:主题二更新
比较好的观察者模式应用是微信公众号,公众号就是我们的主题,粉丝就是观察者。功能如下:
- 1、公众号就是主题,业务就是推送新消息;
- 2、观察者订阅主题,有新的消息自动送来;
- 3、当不想要此主题消息时,取消订阅即可;
总结:
观察者模式的实现方式是在观察者调用主题的addObserver方法将自己添加到主题持有的观察者列表里,主题在需要的时候调用notifyObservers遍历观察者列表,并分别调用观察者的update方法。
打个比方,主题就是婚介所,多个观察者就是多个未婚大龄男青年,男青年注册会员之后将自己的联系方式交给婚介所,婚介所在合适的时候(比如来了适龄女青年),就会挨个给注册的男青年打电话通知。