观察者模式:定义了对象之间一对多的依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。(ps:其实本质上并不是自动更新,还是由主体来触发更新的)
设计原则:为了交互对象之间的松耦合设计而努力。
1 package pattern.observer; 2 3 /** 4 * 主体公共接口 5 * @author CS_Xiaochao 6 * 7 */ 8 public interface Subject { 9 10 void registerObserver(Observers observers); 11 void removeObserver(Observers observers); 12 void notifyObserver(int tempurature); 13 14 }
1 package pattern.observer; 2 3 import java.util.LinkedList; 4 import java.util.List; 5 6 /** 7 * 实现接口的一个主体 8 * @author CS_Xiaochao 9 * 10 */ 11 public class WeatherData implements Subject { 12 13 private Observers observers; 14 private List<Observers> list; 15 16 public WeatherData(){ 17 if(list == null){ 18 list = new LinkedList<Observers>(); 19 } 20 } 21 22 @Override 23 public void registerObserver(Observers observers) { 24 if(list.add(observers)){ 25 System.out.println("注册观察者:" + observers + " 成功!"); 26 } 27 } 28 29 @Override 30 public void removeObserver(Observers observers) { 31 if(list.remove(observers)){ 32 System.out.println("注销观察者:" + observers + " 成功!"); 33 } 34 } 35 36 @Override 37 public void notifyObserver(int tempurature) { 38 for(int i = 0; i < list.size(); i++){ 39 list.get(i).update(tempurature); 40 } 41 } 42 43 }
1 package pattern.observer; 2 3 /** 4 * 观察者公共接口 5 * @author CS_Xiaochao 6 * 7 */ 8 public interface Observers { 9 void update(double tempurature); 10 }
1 package pattern.observer; 2 3 public class TemperatureBoard implements Observers { 4 5 @Override 6 public void update(double tempurature) { 7 System.out.println("当前温度:" + tempurature); 8 } 9 10 }
1 package pattern.observer; 2 3 public class ComitityBoard implements Observers { 4 5 @Override 6 public void update(double tempurature) { 7 System.out.println("当前湿度为:" + Math.sqrt(tempurature)); 8 } 9 10 }
1 package pattern.observer; 2 3 import java.util.Random; 4 5 public class ObserverDemo { 6 7 /** 8 * @param args 9 */ 10 public static void main(String[] args) { 11 12 WeatherData weatherData = new WeatherData(); 13 14 Observers temperatureObserver = new TemperatureBoard(); 15 Observers comitityObserver = new ComitityBoard(); 16 17 weatherData.registerObserver(temperatureObserver); 18 weatherData.registerObserver(comitityObserver); 19 20 //weatherData.removeObserver(comitityObserver); 21 22 Random random = new Random(); 23 for(int i = 0 ; i < 100; i++){ 24 if(random.nextInt(100) % 2 == 0){ 25 weatherData.notifyObserver(random.nextInt(100)); 26 } 27 } 28 } 29 30 }
观察者模式是一对多的依赖关系,其中“一”对应主体,“多”对应观察者(们),也就是说当主体中的内容发生变化时,通过某种机制来通知观察者们,让观察者做一些应对的动作。观察者具有一个公共的接口,接口中定义了观察者公共的方法。所有具体的观察者都可以根据自身的特点来实现接口中的方法。主体中包含了的方法主要是:注册一个观察者,删除一个观察者,通知观察者。主体中存放了所有已注册的观察者的对象,当调用注册方法的时候,就往主体中添加一个新的观察者对象,当调用删除方法时,则将指定的观察者对象从主体中删除,当调用通知方法时,则用此用主体中保存的观察者对象来调用观察者的方法,从而实现当主体发生改变时,观察者作出相应应对的效果。实际上观察者模式往往给人的错觉是:观察者在实时的监听主体,一旦主体有变化,则作出相应应对。事实上观察者并没有去实时的监听主体,而是当主体发生改变的时候,主动的去“通知”观察者们作出相应动作(这里说通知,还不是很恰当,因为观察者每一次作出相应举动,都是主体主动利用存储的观察者对象来调用观察者的方法的,观察者始终处于一个被动的角色,主体利用一个共同的接口来更新观察者)。
补充:上面主要讲了主体(主题、可观察者)向观察者推送数据的方式,实际上也可以让观察者们主动去从主体那里去拿数据,只需要在每一个观察者中保存一份主体的对象,然后调用主体的方法来获得数据即可。但是一般认为被观察者向观察者“推”数据的方式比观察者们从可观察者那里“拿”数据的方式要好。
Java中内置了观察者模式(本人不推荐去使用,自己去实现更加灵活,能加深对于该模式的理解,况且该模式在思想上并不是很难。),Java程序设计语言在很多地方也采用了观察者模式,比较经典的就是在Swing中各种组件对于用户事件的监听。
1 package java.util; 2 3 public class Observable { 4 private boolean changed = false; 5 private Vector obs; 6 7 /** Construct an Observable with zero Observers. */ 8 9 public Observable() { 10 obs = new Vector(); 11 } 12 13 /** 14 * Adds an observer to the set of observers for this object, provided 15 * that it is not the same as some observer already in the set. 16 * The order in which notifications will be delivered to multiple 17 * observers is not specified. See the class comment. 18 * 19 * @param o an observer to be added. 20 * @throws NullPointerException if the parameter o is null. 21 */ 22 public synchronized void addObserver(Observer o) { 23 if (o == null) 24 throw new NullPointerException(); 25 if (!obs.contains(o)) { 26 obs.addElement(o); 27 } 28 } 29 30 /** 31 * Deletes an observer from the set of observers of this object. 32 * Passing <CODE>null</CODE> to this method will have no effect. 33 * @param o the observer to be deleted. 34 */ 35 public synchronized void deleteObserver(Observer o) { 36 obs.removeElement(o); 37 } 38 39 /** 40 * If this object has changed, as indicated by the 41 * <code>hasChanged</code> method, then notify all of its observers 42 * and then call the <code>clearChanged</code> method to 43 * indicate that this object has no longer changed. 44 * <p> 45 * Each observer has its <code>update</code> method called with two 46 * arguments: this observable object and <code>null</code>. In other 47 * words, this method is equivalent to: 48 * <blockquote><tt> 49 * notifyObservers(null)</tt></blockquote> 50 * 51 * @see java.util.Observable#clearChanged() 52 * @see java.util.Observable#hasChanged() 53 * @see java.util.Observer#update(java.util.Observable, java.lang.Object) 54 */ 55 public void notifyObservers() { 56 notifyObservers(null); 57 } 58 59 /** 60 * If this object has changed, as indicated by the 61 * <code>hasChanged</code> method, then notify all of its observers 62 * and then call the <code>clearChanged</code> method to indicate 63 * that this object has no longer changed. 64 * <p> 65 * Each observer has its <code>update</code> method called with two 66 * arguments: this observable object and the <code>arg</code> argument. 67 * 68 * @param arg any object. 69 * @see java.util.Observable#clearChanged() 70 * @see java.util.Observable#hasChanged() 71 * @see java.util.Observer#update(java.util.Observable, java.lang.Object) 72 */ 73 public void notifyObservers(Object arg) { 74 /* 75 * a temporary array buffer, used as a snapshot of the state of 76 * current Observers. 77 */ 78 Object[] arrLocal; 79 80 synchronized (this) { 81 /* We don't want the Observer doing callbacks into 82 * arbitrary code while holding its own Monitor. 83 * The code where we extract each Observable from 84 * the Vector and store the state of the Observer 85 * needs synchronization, but notifying observers 86 * does not (should not). The worst result of any 87 * potential race-condition here is that: 88 * 1) a newly-added Observer will miss a 89 * notification in progress 90 * 2) a recently unregistered Observer will be 91 * wrongly notified when it doesn't care 92 */ 93 if (!changed) 94 return; 95 arrLocal = obs.toArray(); 96 clearChanged(); 97 } 98 99 for (int i = arrLocal.length-1; i>=0; i--) 100 ((Observer)arrLocal[i]).update(this, arg); 101 } 102 103 /** 104 * Clears the observer list so that this object no longer has any observers. 105 */ 106 public synchronized void deleteObservers() { 107 obs.removeAllElements(); 108 } 109 110 /** 111 * Marks this <tt>Observable</tt> object as having been changed; the 112 * <tt>hasChanged</tt> method will now return <tt>true</tt>. 113 */ 114 protected synchronized void setChanged() { 115 changed = true; 116 } 117 118 /** 119 * Indicates that this object has no longer changed, or that it has 120 * already notified all of its observers of its most recent change, 121 * so that the <tt>hasChanged</tt> method will now return <tt>false</tt>. 122 * This method is called automatically by the 123 * <code>notifyObservers</code> methods. 124 * 125 * @see java.util.Observable#notifyObservers() 126 * @see java.util.Observable#notifyObservers(java.lang.Object) 127 */ 128 protected synchronized void clearChanged() { 129 changed = false; 130 } 131 132 /** 133 * Tests if this object has changed. 134 * 135 * @return <code>true</code> if and only if the <code>setChanged</code> 136 * method has been called more recently than the 137 * <code>clearChanged</code> method on this object; 138 * <code>false</code> otherwise. 139 * @see java.util.Observable#clearChanged() 140 * @see java.util.Observable#setChanged() 141 */ 142 public synchronized boolean hasChanged() { 143 return changed; 144 } 145 146 /** 147 * Returns the number of observers of this <tt>Observable</tt> object. 148 * 149 * @return the number of observers of this object. 150 */ 151 public synchronized int countObservers() { 152 return obs.size(); 153 } 154 }
1 package java.util; 2 3 public interface Observer { 4 /** 5 * This method is called whenever the observed object is changed. An 6 * application calls an <tt>Observable</tt> object's 7 * <code>notifyObservers</code> method to have all the object's 8 * observers notified of the change. 9 * 10 * @param o the observable object. 11 * @param arg an argument passed to the <code>notifyObservers</code> 12 * method. 13 */ 14 void update(Observable o, Object arg); 15 }