一:身边的观察者模式
传统的报纸和杂志的订阅就是一种观察者模式:
- 报社的业务就是出版报纸
- 向某家报社订阅报纸,只要他们有新报纸出版,就会给你送来。只要你是他们的订户,你就会一直收到新报纸来。
- 当你不想再看报纸的时候,取消订阅,他们就不会再送新报纸来。
- 只要报社还在运营,就会有人(或单位)向他们订阅报纸或取消订阅报纸。
二:什么是观察者模式
- 由报社和订报人的关系可以看出:出版者+订阅者 = 观察者模式
- 观察者模式:定义了对象之间的一对多依赖,当一个对象改变状态时,它所有的依赖者都会收到通知并自动更新。
-
定义观察者模式
- 《interface》Subject:主题接口,对象使用此接口注册为观察者,或者把自己从观察者中删除。
- ConcreteSubject:具体主题,实现了主题接口,除了注册和撤销方法之外,具体主题还实现了notifyObservers(),此方法用于在状态改变时更新所有当前观察者。
- 《interface》Observer:观察者接口,这个接口只有update()一个方法,当主题状态改变时它被调用。
- Observer:具体观察者,必须注册具体主题,以便接受更新。
当两个对象之间松耦合,他们依然可以交互,但是不太清楚彼此的细节。观察者模式提供了一种对象涉及,让主题和观察者之间松耦合
三:下面我拿lol游戏中的实景来写段代码,体现游戏中的观察者模式(为了更好的理解,我们先不用java内置支持):
主人公:我方中路(solo无解的流浪法师),下路(寄托希望的寒冰箭手),上路(万年蹲的德玛西亚),野区(打野的木木)。
对方中路(高出我们战斗力5000的大神阿卡丽)。
场景:————————————————出门前——————————————————————
寒冰:流浪,对面阿卡丽有点牛逼,她如果中路消失的话你提醒下我啊![此时,寒冰就成了观察者(observe),而流浪则是主题(subject),寒冰向他注册了(registerObserver()),希望阿卡丽gank的时候提醒下自己(notifyObservers())]
流浪:OK![此时,流浪的观察者队列里面已经添加了寒冰]
德玛西亚:¥%¥&%&(……¥%¥ [对流浪说了同样的话,又增加了一个观察者]。
木木:我打野,我不关心 [那他现在就是个路人甲。。]
让我们先来实现主题的接口类:
1 public interface Subject { 2 3 public void registerObserver(Observer o);//注册观察者 4 5 public void removeObserver(Observer o);//解除观察者 6 7 public void notifyObservers();//通知观察者 8 9 }
观察者的接口类:
1 public interface Observer { 2 3 public void update(String alarm);//当被观察者发生变化时,调用观察者的update,把alarm发给观察者。 4 5 public void action();//观察者的行为 6 7 }
流浪:
1 import java.util.ArrayList; 2 3 4 public class RogueMage implements Subject { 5 6 private ArrayList<Observer> observers; 7 private boolean isMiss = false;//阿卡丽是否消失 8 public static String ALARM = "我了个去,阿卡丽不见了!--本条消息来自流浪法师"; 9 public static String SAFE = "她在线上呢!--本条消息来自流浪法师"; 10 public int level; 11 12 public RogueMage() { 13 observers = new ArrayList<Observer>(); 14 } 15 16 @Override 17 public void registerObserver(Observer o) { 18 // TODO Auto-generated method stub 19 if(observers.contains(o) == false){ 20 observers.add(o); 21 } 22 } 23 24 @Override 25 public void removeObserver(Observer o) { 26 // TODO Auto-generated method stub 27 if(observers.contains(o) == true){ 28 observers.remove(o); 29 } 30 } 31 32 @Override 33 public void notifyObservers() { 34 // TODO Auto-generated method stub 35 for(int i = 0;i < observers.size();i++){ 36 observers.get(i).update(ALARM); 37 } 38 } 39 40 private void isMissing(){//阿卡丽消失了 41 System.out.println(ALARM); 42 System.out.println(); 43 System.out.println("-----------------------------------"); 44 notifyObservers(); 45 } 46 47 public void setMissingState(boolean isMiss){//设置阿卡丽状态 48 this.isMiss = isMiss; 49 if(isMiss == true){ 50 isMissing(); 51 } 52 } 53 54 public int getLevel(){//获取阿卡丽等级 55 return level; 56 } 57 58 public void setLevel(int level){//设置阿卡丽等级 59 this.level = level; 60 } 61 }
寒冰:
1 public class FrostArcher implements Observer{ 2 3 private Subject subject; 4 5 public FrostArcher(Subject subject) { 6 this.subject = subject; 7 subject.registerObserver(this); 8 } 9 10 @Override 11 public void update(String alarm) { 12 // TODO Auto-generated method stub 13 if(alarm.equals(RogueMage.ALARM)){ 14 action(); 15 } 16 } 17 18 @Override 19 public void action() { 20 // TODO Auto-generated method stub 21 System.out.println("寒冰射手:好可怕,我还是缩塔好了。"); 22 } 23 24 25 }
德玛西亚:
1 public class Garen implements Observer { 2 private Subject subject; 3 4 public Garen(Subject subject) { 5 this.subject = subject; 6 subject.registerObserver(this); 7 } 8 9 @Override 10 public void update(String alarm) { 11 // TODO Auto-generated method stub 12 if(alarm.equals(RogueMage.ALARM)){ 13 action(); 14 } 15 } 16 17 @Override 18 public void action() { 19 // TODO Auto-generated method stub 20 System.out.println("德玛西亚:我在草丛,她看不见我看不见我~"); 21 } 22 23 }
OK!战斗前准备就绪,全军偷鸡!
1 public class Begin { 2 3 public static void main(String[] agrs){ 4 5 //战斗开始,人物诞生 6 //寒冰和德玛西亚跟流浪法师打招呼,要求阿卡丽消失通知自己 7 RogueMage rogueMage = new RogueMage(); 8 FrostArcher frostArcher = new FrostArcher(rogueMage); 9 Garen garen = new Garen(rogueMage); 10 11 System.out.println("----------战斗开始10分钟,流浪法师发现阿卡丽消失-------------"); 12 rogueMage.setMissingState(true);//流浪法师发现阿卡丽消失。 13 14 } 15 }
结果:
得益于我们简单的观察者模式,阿卡丽第一次gank没有成功,寒冰和德玛西亚他们都躲得远远的,是不是很开心~。
有时候并不是所有的队友会要求别人积极的告诉你关注的消息(推送消息),而且所有人关注的东西都不一样,比如木木,他不怕阿卡丽gank。相反,由于自信,他希望阿卡丽再次gank的时候,自己能从流浪那获取阿卡丽的等级帮助队友反杀,所以我们只好来让木木获得消息(拉取消息)。
木木:
1 public class Sadmummy implements Observer { 2 3 private Subject subject; 4 private RogueMage rogue; 5 6 7 public Sadmummy(Subject subject) { 8 this.subject = subject; 9 if(subject instanceof RogueMage){ 10 rogue = (RogueMage)subject; 11 } 12 subject.registerObserver(this); 13 } 14 15 16 17 @Override 18 public void update(String alarm) { 19 // TODO Auto-generated method stub 20 if(alarm.equals(RogueMage.ALARM)){ 21 action(); 22 } 23 } 24 25 @Override 26 public void action() { 27 // TODO Auto-generated method stub 28 int level = rogue.getLevel(); 29 System.out.println("木木:阿卡丽才"+level+"级,看我去啪啪啪了她"); 30 } 31 32 }
继续玩:
1 public class Begin { 2 3 public static void main(String[] agrs){ 4 5 //战斗开始,人物诞生 6 //寒冰和德玛西亚跟流浪法师打招呼,要求阿卡丽消失通知自己 7 //木木和流浪法师打招呼,要求阿卡丽消失的时候也通知自己 8 RogueMage rogueMage = new RogueMage(); 9 FrostArcher frostArcher = new FrostArcher(rogueMage); 10 Garen garen = new Garen(rogueMage); 11 12 System.out.println("----------战斗开始10分钟,流浪法师发现阿卡丽消失-------------"); 13 rogueMage.setMissingState(true);//流浪法师发现阿卡丽消失。 14 15 16 17 Sadmummy mumumy = new Sadmummy(rogueMage); 18 System.out.println(); 19 System.out.println(); 20 System.out.println("-----------战斗开始20分钟,流浪法师发现阿卡丽再次消失----------"); 21 rogueMage.setLevel(10);//因为木木要知道阿卡丽等级 22 rogueMage.setMissingState(true);//流浪法师发现阿卡丽消失 23 24 25 26 } 27 }
结果:
不出意料,由于用了我们的观察者模式,这次阿卡丽不但没有杀人成功还丢了firstBlood,高手怎么能忍受这耻辱,果断退出了游戏,小伙伴们取得了胜利,喜大普奔啊~
四:代码中的观察者
- 比如button中的listener,当button注册了监听的时候,当界面观察到button被点击则会通知button调用onclick()的方法;
- android中的 BroadcastReceiver注册了监听intent,当系统收到intent符合条件时会通知BroadcastReceiver调用onreceive();
- MVC--模型(model)-视图(view)-控制器(controller),典型的观察者模式。
OO原则:
- 封装变化
- 多用组合,少用继承
- 针对接口编程,不针对实现编程
- 为交互对象之间的松耦合设计而努力