二十五,观察者模式

1.观察者模式介绍

在一对多依赖的对象关系中, 如果这个''对象状态发生了变化,那么它所有依赖的''对象都应该被通知,然后做相应的变化,这就是观察者模式. 就如同''对象一直在观察''对象的状态变化一样.

在观察者模式中最重要的俩个对象分别是:ObservableObserver对象.它们的关系可总结如下:

ObservableObserver对象是一对多的关系,也就是说一旦Observable对象状态变化,它就要负责通知所有和它有关系的Observer对象,然后做相应的改变.

Observable对象不会主动去通知各个具体的Observer对象其状态发生了变化,而是提供一个注册接口供Observer对象使用,任何一个Observer对象如果想要被通知,则可以使用这个接口来注册.

Observable中有一个集合和一个状态控制开关,所有注册了通知的Observer对象会被保存在这个集合中.这个控制开关就是用来控制Observable是否发生了变化,一旦发生了变化,就通知所有的Observer对象更新状态.

javaAPI中分别提供支持

Observable对象:java.util.Observable

Observer接口:java.util.Observer.

2.Observer接口

这个接口只定义了一个方法,update()方法,当被观察者对象的状态发生变化时,被观察者对象的notifyObservers()方法就会调用这一方法.

public interface Observer {

    void update(Observable o, Object arg);

}




3.Observable

被观察者类都是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();
    }
}




3.观察者模式应用

下面用实例来实现一下观察者模式: 股票系统

所有的类如下:

  • StockData (Observable对象,也就是所股票数据发生了变化,它就要通知所有和它有关系的交易实体做相应的变化)
  • BigBuyer (Observer对象, 实现了Observer接口)
  • TradingFool (Observer对象, 实现了Observer接口)
  • StockQuote (测试类)

在这个例子中一旦StockData对象的状态发生了变化,BigBuyerTradingFool都应该受到通知:

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();  
            }  
        }


TradingFool.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代码:
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]

------------------------------------------------


你可能感兴趣的:(观察者模式,observer,Observable)