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