在一对多依赖的对象关系中, 如果这个'一'对象状态发生了变化,那么它所有依赖的'多'对象都应该被通知,然后做相应的变化,这就是观察者模式. 就如同'多'对象一直在观察'一'对象的状态变化一样.
在观察者模式中最重要的俩个对象分别是:Observable和Observer对象.它们的关系可总结如下:
1. Observable和Observer对象是一对多的关系,也就是说一旦Observable对象状态变化,它就要负责通知所有和它有关系的Observer对象,然后做相应的改变.
1. Observable对象不会主动去通知各个具体的Observer对象其状态发生了变化,而是提供一个注册接口供Observer对象使用,任何一个Observer对象如果想要被通知,则可以使用这个接口来注册.
3. 在Observable中有一个集合和一个状态控制开关,所有注册了通知的Observer对象会被保存在这个集合中.这个控制开关就是用来控制Observable是否发生了变化,一旦发生了变化,就通知所有的Observer对象更新状态.
在java api中分别提供了Observable对象:java.util.Observable和Observer接口:java.util.Observer. 下面用实例来实现一下观察者模式: 股票系统
所有的类如下:
StockData (Observable对象,也就是所股票数据发生了变化,它就要通知所有和它有关系的交易实体做相应的变化)
BigBuyer (Observer对象, 实现了Observer接口)
TradingFool (Observer对象, 实现了Observer接口)
StockQuote 测试类
在这个例子中一旦StockData对象的状态发生了变化,那BigBuyer和TradingFool都应该受到通知:
StockData.java:
Java代码
- importjava.util.Observable;
- publicclassStockDataextendsObservable
- {
- privateStringsymbol;
- privatefloatclose;
- privatefloathigh;
- privatefloatlow;
- privatelongvolume;
- publicStockData()
- {}
- publicStringgetSymbol()
- {
- returnsymbol;
- }
- publicfloatgetClose()
- {
- returnclose;
- }
- publicfloatgetHigh()
- {
- returnhigh;
- }
- publicfloatgetLow()
- {
- returnlow;
- }
- publiclonggetVolume()
- {
- returnvolume;
- }
- publicvoidsendStockData()
- {
- setChanged();
- notifyObservers();
- }
- publicvoidsetStockData(Stringsymbol,floatclose,floathigh,floatlow,longvolume)
- {
- this.symbol=symbol;
- this.close=close;
- this.high=high;
- this.low=low;
- this.volume=volume;
- sendStockData();
- }
- }
BigBuyer.java:
Java代码
- publicclassBigBuyerimplementsObserver
- {
- privateStringsymbol;
- privatefloatclose;
- privatefloathigh;
- privatefloatlow;
- privatelongvolume;
- publicBigBuyer(Observableobservable)
- {
- observable.addObserver(this);//注册关系
- }
- publicvoidupdate(Observableobservable,Objectargs)
- {
- if(observableinstanceofStockData)
- {
- StockDatastockData=(StockData)observable;
- this.symbol=stockData.getSymbol();
- this.close=stockData.getClose();
- this.high=stockData.getHigh();
- this.low=stockData.getLow();
- this.volume=stockData.getVolume();
- display();
- }
- }
- publicvoiddisplay()
- {
- DecimalFormatSymbolsdfs=newDecimalFormatSymbols();
- DecimalFormatvolumeFormat=newDecimalFormat("###,###,###,###",dfs);
- DecimalFormatpriceFormat=newDecimalFormat("###.00",dfs);
- System.out.println("BigBuyerreports...");
- System.out.println("\tThelasteststockquotefor"+symbol+"is:");
- System.out.println("\t$"+priceFormat.format(close)+"pershare(close).");
- System.out.println("\t$"+priceFormat.format(high)+"pershare(high).");
- System.out.println("\t$"+priceFormat.format(low)+"pershare(low).");
- System.out.println("\t"+volumeFormat.format(volume)+"sharestraded.");
- System.out.println();
- }
- }
TradingFool.java:
Java代码
- publicclassTradingFoolimplementsObserver
- {
- privateStringsymbol;
- privatefloatclose;
- publicTradingFool(Observableobservable)
- {
- observable.addObserver(this);//注册关系
- }
- publicvoidupdate(Observableobservable,Objectargs)
- {
- if(observableinstanceofStockData)
- {
- StockDatastockData=(StockData)observable;
- this.symbol=stockData.getSymbol();
- this.close=stockData.getClose();
- display();
- }
- }
- publicvoiddisplay()
- {
- DecimalFormatSymbolsdfs=newDecimalFormatSymbols();
- DecimalFormatpriceFormat=newDecimalFormat("###.00",dfs);
- System.out.println("TradingFoolsays...");
- System.out.println("\t"+symbol+"iscurrentlytradingat$"+priceFormat.format(close)+"pershare.");
- System.out.println();
- }
- }
StokeQuote.java
Java代码
- publicclassStockQuotes
- {
- publicstaticvoidmain(String[]args)
- {
- System.out.println();
- System.out.println("--StockQuoteApplication--");
- System.out.println();
- StockDatastockData=newStockData();
- //registerobservers...
- newTradingFool(stockData);
- newBigBuyer(stockData);
- //generatechangestostockdata...
- 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对象就会做相应的更新了, 运行结果如下:
Java代码
- BigBuyerreports...
- ThelasteststockquoteforJUPMis:
- $16.10pershare(close).
- $16.15pershare(high).
- $15.34pershare(low).
- 481,172sharestraded.
- TradingFoolsays...
- JUPMiscurrentlytradingat$16.10pershare.
- BigBuyerreports...
- ThelasteststockquoteforSUNWis:
- $4.84pershare(close).
- $4.90pershare(high).
- $4.79pershare(low).
- 68,870,233sharestraded.
- TradingFoolsays...
- SUNWiscurrentlytradingat$4.84pershare.
- BigBuyerreports...
- ThelasteststockquoteforMSFTis:
- $23.17pershare(close).
- $23.37pershare(high).
- $23.05pershare(low).
- 75,091,400sharestraded.
- TradingFoolsays...
- MSFTiscurrentlytradingat$23.17pershare.
我们通过Observable源码可以看到,其实Observable对象不关心具体的Observer的实例类型. 只要是实现了Observer接口的Observer对象都可以得到通知,这就为我们如果想要对模型进行扩展提供了方便,使Observable对象和Observer对象实现了松耦合. 如果我们需要添加一个新的Observer对象时,我们只要注册一下,当Observable对象发生变化时就可以得到通知,而不要做其他任何改变,非常方便.