观察者(Observer)模式

观察者(Observer)模式

观察者(Observer)模式是对象的行为型模式,又叫做发表-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-收听者(Source/Listener)模式或从属者(Dependents)模式。

在观察者模式里有如下的角色:

抽象主题(Subject)角色

                               主题角色把所有的观察者对象的引用保存在一个列表里;每个主题都可以有任何数量的观察者。

                               主题提供一个接口可以加上或撤销观察者对象;主题角色又叫做抽象被观察者(Observable)角色

抽象观察者(Observer)角色

                               为所有的具体观察者定义一个接口,在得到通知时更新自己;

具体主题(ConcreteSubject)角色

                               保存对具体观察者对象有用的内部状态;在这种内部状态改变时给其观察者发出一个通知;具体主题角色又叫作具体被观察者角色;

具体观察者(ConcreteObserver)角色

                               保存一个指向具体主题对象的引用;和一个与主题的状态相符的状态。具体观察者角色实现抽象观察者角色所要求的更新自己的接口,

                               以便使本身的状态与主题的状态自恰。

示例摘自:http://blog.csdn.net/legendmohenote/article/details/5762350

其实在JDK中提供了一个Observable类,一个Observer接口,在此基础丰富自己的内容。

    public class Observable {   
        private boolean changed = false;   
        private Vector obs;   
          
        //创建被观察者时就创建一个它持有的观察者列表,注意,这个列表是需要同步的。   
        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);   
        }   
        /**  
         * 与上面的那个通知方法不同的是,这个方法接受一个参数,这个参数一直传到观察者里,以供观察者使用 
         */  
        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);   
        }   
    }  
这里只列出了一些常用的操作,大家如有不明白可以自己看 java.util包下的Observable,每一个方法前都有详细的解释。但是以上列出的方法对于这个例子来说已经够用了。
当我们自己的被观察者继承这个Observable类是,我们就自动的获取到被观察者的一切条件了。很方便是不是,这也是为什么sun要把Observable放到 java.util包中的原因,就是为了方便开发者。
讲完了被观察者再让我们来看看观察者,在上面的代码中有一个addObserver(Observer o)方法,由此我们可以看出来,给被观察者添加观察者时就是用这个方法,那么也就是说观察者一定是Observer的子类或者实现,我们看一下 java.util.Observer吧

    public interface Observer {   
        /**  
         * This method is called whenever the observed object is changed. An  
         * application calls an <tt>Observable</tt> object's  
         * <code>notifyObservers</code> method to have all the object's  
         * observers notified of the change.  
         *  
         * @param   o     the observable object.  
         * @param   arg   an argument passed to the <code>notifyObservers</code>  
         *                 method.  
         */  
        void update(Observable o, Object arg);   
    }   
    }  
很好,这是一个接口,接口中就只有一个方法,update,方法中有两个参数,Observable和一个object,第一个参数就是被观察的对象,而第二个参数就得看业务需求了,需要什么就传进去什么。我们自己的观察者类必须实现这个方法,这样在被观察者调用notifyObservers操作时被观察者所持有的所有观察者都会执行update操作了(当然如果你override这个方法,你甚至可以指定何种情况下只执行某种observer了,是不是比较像责任链模式了)。 

那么到这里我们也差不多可以把观察者模式应用到项目中去了。首先让我们来实现被观察者(因为实现被观察者非常简单)

public class MailObserver implements Observer{   
  
    /**  
     * 这个类取名为MailObserver,顾名思义,她是一个用来发送邮件的观察者  
     */  
    public void update(Observable o, Object arg) {   
        System.out.println("发送邮件的观察者已经被执行");   
    }   
}  
public class JMSObserver implements Observer{   
  
    public void update(Observable o, Object arg) {   
        System.out.println("发送消息给jms服务器的观察者已经被执行");   
    }   
}  
如上所见,观察者的实现完全跟业务相关。是否复杂就得看你得业务是否复杂了。 

接下来让我们再来实现被观察者,示例如下:
public class Subject extends Observable{   
       
    /**  
     * 业务方法,一旦执行某个操作,则通知观察者  
     */  
    public void doBusiness(){   
        if (true) {   
            super.setChanged();   
        }   
        notifyObservers("现在还没有的参数");   
    }   
    public static void main(String [] args) {   
        //创建一个被观察者   
        Subject subject = new Subject();   
           
        //创建两个观察者   
        Observer mailObserver = new MailObserver();   
        Observer jmsObserver = new JMSObserver();   
           
        //把两个观察者加到被观察者列表中   
        subject.addObserver(mailObserver);   
        subject.addObserver(jmsObserver);   
           
        //执行业务操作   
        subject.doBusiness();   
    }   
}  
到此为止,我们已经简单得实现了 观察者模式,让我们来运行一下上面main方法,运行结果如下: 

发送消息给jms服务器的观察者已经被执行 
发送邮件的观察者已经被执行 

有了jdk对 观察者模式的支持,程序员在实现基本的 观察者模式时应该说是易如反掌,这也从一个侧面反应出 观察者模式的地位,它的地位应该是非常重要的

如果上面的例子比较零散,那下面给出一个比较完整的例子

在java   api中分别提供了Observable对象:java.util.Observable和Observer接口:java.util.Observer.下面用实例来实现一下观察者模式: 股票系统

所有的类如下:

StockData (Observable对象,也就是所股票数据发生了变化,它就要通知所有和它有关系的交易实体做相应的变化)

BigBuyer (Observer对象, 实现了Observer接口)

TradingFool (Observer对象, 实现了Observer接口)

StockQuote 测试类

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

package com.zhj.observer1;
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 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();
    }
//setChanged();说明有变更,notifyObservers();通知注入过的观察者调用update方法
    public void sendStockData() {
        setChanged();
        notifyObservers();
    }

    。。。。这里省略setter getter方法

}
观察者BigBuyer.java:
package com.zhj.observer1;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Observable;
import java.util.Observer;
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);
    }
    @Override
    public void update(Observable observable, Object arg) {
        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:
package com.zhj.observer1;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Observable;
import java.util.Observer;
public class TradingFool implements Observer {
    private String symbol;
    private float close;
//在初始化构造的时候,传入被观察者对象,将本对象加入到观察者列表中
 public TradingFool(Observable observable) {
observable.addObserver(this);
}
@Override
public void update(Observable observable, Object arg) {
  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
package com.zhj.observer1;
public class StokeQuote {
public static void main(String[] args) {
System.out.println();
System.out.println("-- Stock Quote Application --");
System.out.println();
//创建被观察者
StockData stockData = new StockData();
//创建两个观察者
new TradingFool(stockData);
new BigBuyer(stockData);
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);
}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值