在一对多依赖的对象关系中, 如果这个'一'对象状态发生了变化,那么它所有依赖的'多'对象都应该被通知,然后做相应的变化,这就是观察者模式. 就如同'多'对象一直在观察'一'对象的状态变化一样.
在观察者模式中最重要的俩个对象分别是:Observable和Observer对象.它们的关系可总结如下:
①Observable和Observer对象是一对多的关系,也就是说一旦Observable对象状态变化,它就要负责通知所有和它有关系的Observer对象,然后做相应的改变.
②Observable对象不会主动去通知各个具体的Observer对象其状态发生了变化,而是提供一个注册接口供Observer对象使用,任何一个Observer对象如果想要被通知,则可以使用这个接口来注册.
③在Observable中有一个集合和一个状态控制开关,所有注册了通知的Observer对象会被保存在这个集合中.这个控制开关就是用来控制Observable是否发生了变化,一旦发生了变化,就通知所有的Observer对象更新状态.
在javaAPI中分别提供支持
Observable对象:java.util.Observable
Observer接口:java.util.Observer.
这个接口只定义了一个方法,即update()方法,当被观察者对象的状态发生变化时,被观察者对象的notifyObservers()方法就会调用这一方法.
public interface Observer { void update(Observable o, Object arg); }
被观察者类都是java.util.Observable类的子类.java.util.Observable提供公开的方法支持观察者对象,这些方法中有两个对Observable的子类非常重要:一个是setChanged(),另一个是notifyObservers().第一方法setChanged()被调用之后会设置一个内部标记变量,代表被观察者对象的状态发生了变化.第二个是notifyObservers(),这个方法被调用时,会调用所有登记过的观察者对象的update()方法,使这些观察者对象可以更新自己.
源码:
public class Observable { private boolean changed = false; private Vector obs; /** Construct an Observable with zero Observers. */ 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); } /** * 如果本对象有变化(那时hasChanged 方法会返回true) * 调用本方法通知所有登记的观察者,即调用它们的update()方法 * 传入this和arg作为参数 */ 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(); } /** * 将“已变化”设置为true */ protected synchronized void setChanged() { changed = true; } /** * 将“已变化”重置为false */ protected synchronized void clearChanged() { changed = false; } /** * 检测本对象是否已变化 */ public synchronized boolean hasChanged() { return changed; } /** * Returns the number of observers of this <tt>Observable</tt> object. * * @return the number of observers of this object. */ public synchronized int countObservers() { return obs.size(); } }
下面用实例来实现一下观察者模式: 股票系统
所有的类如下:
在这个例子中一旦StockData对象的状态发生了变化,那BigBuyer和TradingFool都应该受到通知:
StockData.java代码:
import java.util.Observable; public class StockData extends Observable { private String symbol; private float close; private float high; private float low; private long volume; public StockData() {} public String getSymbol() { return symbol; } public float getClose() { return close; } public float getHigh() { return high; } public float getLow() { return low; } public long getVolume() { return volume; } public void sendStockData() { setChanged(); notifyObservers(); } public void setStockData(String symbol,float close,float high,float low,long volume) { this.symbol = symbol; this.close = close; this.high = high; this.low = low; this.volume = volume; sendStockData(); } }
BigBuyer.java代码:
public class BigBuyer implements Observer { private String symbol; private float close; private float high; private float low; private long volume; public BigBuyer(Observable observable) { observable.addObserver(this); //注册关系 } public void update(Observable observable,Object args) { if(observable instanceof StockData) { StockData stockData = (StockData)observable; this.symbol = stockData.getSymbol(); this.close = stockData.getClose(); this.high = stockData.getHigh(); this.low = stockData.getLow(); this.volume = stockData.getVolume(); display(); } } public void display() { DecimalFormatSymbols dfs = new DecimalFormatSymbols(); DecimalFormat volumeFormat = new DecimalFormat("###,###,###,###",dfs); DecimalFormat priceFormat = new DecimalFormat("###.00",dfs); System.out.println("Big Buyer reports..."); System.out.println("\tThe lastest stock quote for " + symbol + " is:"); System.out.println("\t$" + priceFormat.format(close) + " per share (close)."); System.out.println("\t$" + priceFormat.format(high) + " per share (high)."); System.out.println("\t$" + priceFormat.format(low) + " per share (low)."); System.out.println("\t" + volumeFormat.format(volume) + " shares traded."); System.out.println(); } }
public class TradingFool implements Observer { private String symbol; private float close; public TradingFool(Observable observable) { observable.addObserver(this);//注册关系 } public void update(Observable observable,Object args) { if(observable instanceof StockData) { StockData stockData = (StockData)observable; this.symbol = stockData.getSymbol(); this.close = stockData.getClose(); display(); } } public void display() { DecimalFormatSymbols dfs = new DecimalFormatSymbols(); DecimalFormat priceFormat = new DecimalFormat("###.00",dfs); System.out.println("Trading Fool says..."); System.out.println("\t" + symbol + " is currently trading at $" + priceFormat.format(close) + " per share."); System.out.println(); } }
public class StockQuotes { public static void main(String[] args) { System.out.println(); System.out.println("-- Stock Quote Application --"); System.out.println(); StockData stockData = new StockData(); // register observers... new TradingFool(stockData); new BigBuyer(stockData); // generate changes to stock data... stockData.setStockData("JUPM",16.10f,16.15f,15.34f,(long)481172); stockData.setStockData("SUNW",4.84f,4.90f,4.79f,(long)68870233); stockData.setStockData("MSFT",23.17f,23.37f,23.05f,(long)75091400); } }
在测试类中我们可以看到俩个Observer对象都注册了Observable对象,而当Observable对象发生改变时,这俩个Observable对象就会做相应的更新了, 运行结果如下:
Big Buyer reports... The lastest stock quote for JUPM is: $16.10 per share (close). $16.15 per share (high). $15.34 per share (low). 481,172 shares traded. Trading Fool says... JUPM is currently trading at $16.10 per share. Big Buyer reports... The lastest stock quote for SUNW is: $4.84 per share (close). $4.90 per share (high). $4.79 per share (low). 68,870,233 shares traded. Trading Fool says... SUNW is currently trading at $4.84 per share. Big Buyer reports... The lastest stock quote for MSFT is: $23.17 per share (close). $23.37 per share (high). $23.05 per share (low). 75,091,400 shares traded. Trading Fool says... MSFT is currently trading at $23.17 per share.我们通过 Observable源码可以看到 ,其实 Observable对象不关心具体的 Observer的实例类型 .只要是实现了 Observer接口的 Observer对象都可以得到通知 ,这就为我们如果想要对模型进行扩展提供了方便 ,使 Observable对象和 Observer对象实现了松耦合 .如果我们需要添加一个新的 Observer对象时 ,我们只要注册一下 ,当 Observable对象发生变化时就可以得到通知 ,而不要做其他任何改变 ,非常方便 .
参考
http://zhanghong.iteye.com/blog/1021092
http://www.cnblogs.com/java-my-life/archive/2012/05/16/2502279.html
20150503
JAVA学习笔记系列
--------------------------------------------
联系方式
--------------------------------------------
Weibo: ARESXIONG
E-Mail: [email protected]
------------------------------------------------