Java中觀察者模式的使用
在一對多依賴的對象關系中, 如果這個'一'對象狀態(tài)發(fā)生了變化,那么它所有依賴的'多'對象都應該被通知,然后做相應的變化,這就是觀察者模式. 就如同'多'對象一直在觀察'一'對象的狀態(tài)變化一樣.
在觀察者模式中最重要的倆個對象分別是:Observable和Observer對象.它們的關系可總結(jié)如下:
1. Observable和Observer對象是一對多的關系,也就是說一旦Observable對象狀態(tài)變化,它就要負責通知所有和它有關系的Observer對象,然后做相應的改變.
1. Observable對象不會主動去通知各個具體的Observer對象其狀態(tài)發(fā)生了變化,而是提供一個注冊接口供Observer對象使用,任何一個Observer對象如果想要被通知,則可以使用這個接口來注冊.
3. 在Observable中有一個集合和一個狀態(tài)控制開關,所有注冊了通知的Observer對象會被保存在這個集合中.這個控制開關就是用來控制Observable是否發(fā)生了變化,一旦發(fā)生了變化,就通知所有的Observer對象更新狀態(tài).
在java api中分別提供了Observable對象:java.util.Observable和Observer接口:java.util.Observer. 下面用實例來實現(xiàn)一下觀察者模式: 股票系統(tǒng)
所有的類如下:
StockData (Observable對象,也就是所股票數(shù)據(jù)發(fā)生了變化,它就要通知所有和它有關系的交易實體做相應的變化)
BigBuyer (Observer對象, 實現(xiàn)了Observer接口)
TradingFool (Observer對象, 實現(xiàn)了Observer接口)
StockQuote 測試類
在這個例子中一旦StockData對象的狀態(tài)發(fā)生了變化,那BigBuyer和TradingFool都應該受到通知:
StockData.java:
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:
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();
- }
- }
TradingFool.java:
Java代碼
- 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();
- }
- }
StokeQuote.java
Java代碼
- 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對象發(fā)生改變時,這倆個Observable對象就會做相應的更新了, 運行結(jié)果如下:
Java代碼
- 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的實例類型. 只要是實現(xiàn)了Observer接口的Observer對象都可以得到通知,這就為我們?nèi)绻胍獙δP瓦M行擴展提供了方便,使Observable對象和Observer對象實現(xiàn)了松耦合. 如果我們需要添加一個新的Observer對象時,我們只要注冊一下,當Observable對象發(fā)生變化時就可以得到通知,而不要做其他任何改變,非常方便.
【編輯推薦】