博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
二十五,观察者模式
阅读量:7287 次
发布时间:2019-06-30

本文共 8985 字,大约阅读时间需要 29 分钟。

hot3.png

1.观察者模式介绍

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

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

Observable和Observer对象是一对多的关系,也就是说一旦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 Observable 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对象的状态发生了变化,那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();              }          }

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对象发生变化时就可以得到通知 ,而不要做其他任何改变 ,非常方便 .

参考

20150503

JAVA学习笔记系列

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

                    联系方式

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

        Weibo: ARESXIONG

        E-Mail: aresxdy@gmail.com

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

转载于:https://my.oschina.net/u/2288529/blog/410143

你可能感兴趣的文章
Glusterfs初体验
查看>>
Centos搭建SVN服务器三步曲
查看>>
NC-ERP IUFO系统管理要点
查看>>
linux下将文件设置为swap
查看>>
jquery filter()方法
查看>>
make和makefile
查看>>
eclipse git 强制覆盖本地文件
查看>>
elasticsearch查询关键字slop
查看>>
[Unity3d]Player Settings导出设置
查看>>
Python成长之路第一篇(2)-初识列表和元组
查看>>
Docker EE/Docker CE简介与版本规划
查看>>
python 读取excel中的数据
查看>>
(转)java.util.zip.ZipException
查看>>
CENTOS 设置文件夹打开方式:在同一窗口打开文件夹
查看>>
ubuntu 64 装db2 v9.7 server
查看>>
顶级操作系统会议——2009年SOSP会议概况介绍
查看>>
display:table-cell实现两栏自适应布局
查看>>
mysql 读写分离mysql-proxy 代理
查看>>
httpd+tomcat(3) -- mod_jk
查看>>
MySQL:卸载、安装MySQL8.***
查看>>