Java观察者模式(Observer)详解及应用------模式中的皇后

       

一、概述

  Java的设计模式很多,观察者模式被称为是模式中的皇后,而且Java jdk也对它做了实现,可见该设计模式的重要位置。在图形化设计的软件中,为了实现视图和事件处理的分离,大多都采用了Observer模式,比如Java的Swing,Flex的ActionScript等。在现实的应用系统中也有好多应用,比如像当当网、京东商城一类的电子商务网站,如果你对某件商品比较关注,可以放到收藏架,那么当该商品降价时,系统给您发送手机短信或邮件。这就是观察者模式的一个典型应用,商品是被观察者,有的叫主体;关注该商品的客户就是观察者。下面的一个事例将模拟这个应用。

 

  GoF说道:Observer模式的意图是“定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新”。从这段话里我们可以得到两个信息,如下:

 

1,观察者(具体执行操作的对象,有多个)

2,被观察者(顾名思义是被观察的对象,如果该对象发生某些变化则通知观察者执行对应的操)

 

二、jdk中观察者模式解析

 

  在java的util包中实现了该设计模式的框架,大部分应用都可以直接用它,当然了你也可以自己实现它,实际上就是一个被观察者的抽象类和一个观察者接口。我们先看一下jdk是如何实现的。被观察者的抽象类java.util.Observable

 

packagejava.util;

publicclass Observable {

    private boolean changed = false;

    private Vector obs;

  

  //创建被观察者时就创建一个它持有的观察者列表,注意,这个列表是需要同步的。

    public Observable() {

         obs = new Vector();

    }

 

     /** 

     * 添加观察者到观察者列表中去 

     */ 

    public synchronized voidaddObserver(Observer o) {

        if (o == null)

            throw new NullPointerException();

         if (!obs.contains(o)) {

            obs.addElement(o);

         }

    }

 

     /** 

     * 删除一个观察者 

     */  

    public synchronized voiddeleteObserver(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);

    }

 

 

    public synchronized void deleteObservers(){

         obs.removeAllElements();

    }

 

    protected synchronized void setChanged() {

         changed = true;

    }

 

    protected synchronized void clearChanged(){

         changed = false;

    }

 

 

    public synchronized boolean hasChanged() {

         return changed;

    }

 

    public synchronized int countObservers() {

         return obs.size();

    }

}

 

 

当我们自己的被观察者继承这个Observable类是,我们就自动的获取到被观察者的一切条件了。很方便是不是,这也是为什么sun要把Observable放到java.util包中的原因,就是为了方便开发者。

 

下面我们再看一下观察者的接口java.util.Observer

 

packagejava.util;

 

publicinterface Observer {

 

    void update(Observable o, Object arg);

}

接口中就只有一个方法,update,方法中有两个参数,Observable和一个object,第一个参数就是被观察的对象,而第二个参数就得看业务需求了,需要什么就传进去什么。我们自己的观察者类必须实现这个方法,这样在被观察者调用notifyObservers操作时被观察者所持有的所有观察者都会执行update操作了.

 

三、观察者模式应用

 

下面是一个book对象,它是一个被观察者,所以要继承Observable

import java.util.Observable;

public class Book extends Observable {

 

    private String name = "";

    private double price = 0.0;

    public String getName() {

       return name;

    }

    public void setName(String name) {

       this.name = name;

    }

 

    public double getPrice() {

       return price;

    }

    public void setPrice(double price) {

       this.price = price;

    }

    //当书的价格修改时调用该方法

    public void modifyPrice(Book b) {

       //调用父类的方法,改变被观察者的状态 

       setChanged();

       //通知客户该书已降价

       notifyObservers(b);

    }

 

}

 

下面是观察者对象,表示顾客的电子邮件,它实现了Observer接口。

importjava.util.Observable;

importjava.util.Observer;

publicclass BuyerEmail implements Observer {

 

         private String buyerId = "";

         private String email = "";

 

         public String getBuyerId() {

                   return buyerId;

         }

         public void setBuyerId(String buyerId){

                   this.buyerId = buyerId;

         }

         public String getEmail() {

                   return email;

         }

         public void setEmail(String email) {

                   this.email = email;

         }

  //该方法会被“被观察者的父类”既Observable调用

         public void update(Observable o, Objectarg) {

                   //这里做具体发电子邮件的操作

                    Book b = (Book)arg;

                   System.out.println("给顾客的发电子邮件:"+b.getName()+"降价了,目前价格为:"+b.getPrice());

         }

}

 

下面是另一个观察者对象,表示顾客的手机,同样需要继承Observer接口

importjava.util.Observable;

importjava.util.Observer;

publicclass BuyerMobileMessage implements Observer {

 

         private String buyerId = "";

         private String mobileNo = "";

 

         public String getBuyerId() {

                   return buyerId;

         }

         public void setBuyerId(String buyerId){

                   this.buyerId = buyerId;

         }

         public String getMobileNo() {

                   return mobileNo;

         }

         public void setMobileNo(StringmobileNo) {

                   this.mobileNo = mobileNo;

         }

         public void update(Observable o, Objectarg) {

                   // TODO Auto-generated methodstub

                   Book b = (Book)arg;

                   System.out.println("给顾客的发手机短信:"+b.getName()+"降价了,目前价格为:"+b.getPrice());

         }

}

 

下面是调用类:

 

public class MainApp {

 

    public static void main(String args[])

    {

       Book b1 = new Book();

       b1.setName("<<Java设计模式>>");

       b1.setPrice(45.00);//假设原价是60,现在是降价促销

      

       //下面的观察者在实际的应用中可以从数据库或文件中读取

       BuyerMobileMessage bm = new BuyerMobileMessage();

       bm.setBuyerId("001");

       bm.setMobileNo("13810500085");

      

       BuyerEmail be = new BuyerEmail();

       be.setBuyerId("001");

       be.setEmail("dobodo@163.com");

      

       //增加观察者,在实际应用中就是那些人对该书做了关注

       b1.addObserver(bm);

       b1.addObserver(be);

      

       b1.modifyPrice(b1);

    }

}

 

输出:

给顾客的发电子邮件:<<Java设计模式>>降价了,目前价格为:45.0

给顾客的发手机短信:<<Java设计模式>>降价了,目前价格为:45.0

 

  不知道上面的例子你看懂了没有,观察者模式实际上没什么高深的东西,就是运用了java的继承和接口,在被观察者的抽象类里设置一个状态标志,通过该标志判断是否通知观察者对象。在学习该模式的同时,我们更应该学习java的继承和接口的灵活应用,其实所有的设计模式都是继承、接口、多态的灵活应用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值