设计模式-观察者模式(Observer Model)
文 / vincentzh
原文连接:http://www.cnblogs.com/vincentzh/p/6031844.html
LZ刚刚开始心热的开启了博客之路,想着记点流水账,可帝都的天都冷成狗了一样,还特么不供暖,冻的打字都感觉不到键盘在哪里。。。
目录
1、概述
观察者模式通俗讲就是一堆观察者对象同时观察一个对象的状态。好比一妹子后面跟了一群追求者,妹子一看,这仨还错,有才华、有相貌、有money,先允许你们三来竞争吧。姑娘口渴了,仨小伙急了,纷纷去给姑娘去买水,又是矿泉水又是饮料的。
2、原理
观察者模式的原理比较简单,类似于监听,定义了一种一对多的关系,让多个观察者同时监听一个主题对象,当主题角色状态发生变化时,会通知所有观察者对象,使它们去自行更新。
3、结构组成
观察者模式原理简单,但结构上还是稍微有点绕。其包含了4个角色:
抽象主题角色(Subject):抽象主题角色只提供一个接口,它将所有的观察者引用保存再一个容器里,同时提供增加观察者、删除观察者、通知所有观察者的方法;
具体主题角色(ConcreteSubject):具体主题角色提供一个容器保存所有观察者的引用,当其状态发生改变时,会通知在其容器内登记过的所有观察者;
抽象观察者角色(Observer):抽象观察者角色为具体观察者角色定义了一个接口,它提供了具体观察者角色更新自己的方法;
具体观察者角色(ConcreteObserver):具体观察者角色实现了抽象观察者角色定义的更新方法,以更新自己状态和主题角色状态一致,或着说相应主题角色状态的改变。
4、实现
观察者模式的实现在4.1这里举了个例子,有点牵强,但能说明问题;4.2是利用JDK提供的接口和类去实现的观察者模式。
4.1 场景案例
年关将至,镇长下乡去视察,看看下属各个村儿里今年的收入情况怎么样,群众有没有赚到钱呀,庄稼收成好不好呀,bulabula...。各村儿一听镇长要下乡,好家伙,赶紧趁这个机会好好表现表现,说不定明年镇长能多给村儿里几个低保名额。A村提前给镇长就做好了热腾腾的裤带面,B村知道领导都好面子,老早就搞起了锣鼓队给领导办欢迎仪式。
抽象观察者类:
1 package com.cnblogs.vincentzh.observer; 2 // 抽象观察者角色(村儿接口) 3 public interface Villages 4 { 5 public void action(String str); 6 }
抽象主题类:
1 package com.cnblogs.vincentzh.observer; 2 // 抽象主题角色(领导接口) 3 public interface LeaderShip 4 { 5 public boolean add(Villages village); 6 public boolean delete(Villages village); 7 public void notify(String str); 8 }
具体主题类:
1 package com.cnblogs.vincentzh.observer; 2 3 import java.util.HashSet; 4 // 具体主题角色(镇长) 5 public class Mayor implements LeaderShip 6 { 7 // 观察者容器 8 public HashSet<Villages> villages = new HashSet<Villages>(); 9 10 @Override 11 public boolean add(Villages village) 12 { 13 return villages.add(village); 14 } 15 16 @Override 17 public boolean delete(Villages village) 18 { 19 return villages.remove(village); 20 } 21 22 @Override 23 public void notify(String str) 24 { 25 for(Villages village : villages) 26 { 27 village.action(str); 28 } 29 } 30 }
具体观察者类:
1 package com.cnblogs.vincentzh.observer; 2 // 具体观察者角色(村儿) 3 public class Village implements Villages 4 { 5 private String string; 6 7 public Village(String string) 8 { 9 this.string = string; 10 } 11 12 @Override 13 public void action(String str) 14 { 15 System.out.println(str); 16 System.out.println(string + " for LeaderShip"); 17 } 18 }
环境测试类:
1 package com.cnblogs.vincentzh.observer; 2 // 环境测试类 3 public class Test 4 { 5 /** 6 * @param args 7 */ 8 public static void main(String[] args) 9 { 10 LeaderShip mayor = new Mayor(); 11 12 Village village1 = new Village("village1: We cooking"); // A村做饭 13 Village village2 = new Village("village2: We welcome"); // B村欢迎 14 15 mayor.add(village1); 16 mayor.add(village2); 17 mayor.notify("Mayor is comming!"); 18 19 System.out.println("------------------------------"); 20 mayor.delete(village1); 21 mayor.notify("Mayor is comming!"); 22 } 23 }
结果:
4.2 JDK实现
JDK内部提供了用于实现观察者模式的Observable 类和 Observer 接口,它们分别充当了抽象主题角色和抽象观察者角色,要实现观察者模式,只需要定义具体主题类并继承 Observable 类重写相应的方法,同时定义具体观察者对象实现 Observer 接口并实现其中的更新方法即可。
具体主题类:
1 package com.cnblogs.vincentzh.observermodel; 2 3 import java.util.HashSet; 4 import java.util.Observable; 5 import java.util.Observer; 6 // 具体主题角色(及被观察者) 7 public class Watched extends Observable 8 { 9 // 观察者容器 10 private HashSet<Observer> sets = new HashSet<Observer>(); 11 12 @Override 13 public synchronized void addObserver(Observer o) 14 { 15 sets.add(o); 16 } 17 18 @Override 19 public synchronized void deleteObserver(Observer o) 20 { 21 sets.remove(o); 22 } 23 24 @Override 25 public void notifyObservers() 26 { 27 for(Observer observer : sets) 28 { 29 observer.update(this, this); 30 } 31 } 32 }
具体观察者类:
1 package com.cnblogs.vincentzh.observermodel; 2 3 import java.util.Observable; 4 import java.util.Observer; 5 // 观察者角色(即观察者) 6 public class Watcher implements Observer 7 { 8 private String str; 9 10 public Watcher(String str) 11 { 12 this.str = str; 13 } 14 15 @Override 16 public void update(Observable o, Object arg) 17 { 18 System.out.println((String)str); 19 } 20 }
环境测试类:
1 package com.cnblogs.vincentzh.observermodel; 2 // 环境测试类 3 public class Test 4 { 5 public static void main(String[] args) 6 { 7 Watcher watcher1 = new Watcher("watched1"); 8 Watcher watcher2 = new Watcher("watched2"); 9 10 Watched watched = new Watched(); 11 12 watched.addObserver(watcher1); 13 watched.addObserver(watcher2); 14 watched.notifyObservers(); 15 16 System.out.println("---------------------------"); 17 18 watched.deleteObserver(watcher1); 19 watched.notifyObservers(); 20 } 21 }
结果:
5、总结
观察者模式对主题对象和观察者对象进行了解耦,使双方都依赖于抽象,而并不是依赖于对方的具体对象,使得双方各自的变化都不会影响到对方的具体对象。但双方并没有完全的独立,抽象主题通知时仍然依赖于抽象观察者。当其他多个对象需要根据一个对象的状态发生相应的改变或操作时(或类似发布/订阅模式),可使用观察者模式来解决。