java中的观察者模式

最近在学习《head first 设计模式》,站在巨人的肩膀上学习设计模式,一定会有很大的收获。通过了解设计模式的uml图,来看java源码,让我对java中的一些实现又多了更深层次的了解。在这里,也记录一下学习历程,并与大家分享学习心得。

观察者模式的类图

  • 观察者模式运用接口和组合的方式来进行设计。
  • 类似于报纸的订阅,被订阅信息称为主题(Subject),订阅者称为观察者。当主题有更新时,会通知观察者。
  • 主题和观察者之间是多对一的关系。一个主题可以引入多个观察者对象。
    这里写图片描述

java中的观察者模式

java中专门提供了一个观察者模式的API,有时候用到观察者的设计思想时,可以继承java中的Observable类来实现。

使用例子

实现一个主题类
public class PaperObservable extends Observable{
    private String date;
    private String title;
    private String content;

    public void todayNewsChange(){
        setChanged();
        notifyObservers();
    }
    public void setTodayNews(String date,String title,String content){
        this.date = date;
        this.title = title;
        this.content = content;
    }
    public void getObserversCount(){
        int count = super.countObservers();
        System.out.println("当前订阅者:"+count);
    }

    @Override
    public String toString() {
        return "PaperObservable{" +
                "date='" + date + '\'' +
                ", title='" + title + '\'' +
                ", content='" + content + '\'' +
                '}';
    }
}

注意 这里有个在调用通知方法之前要设置setChanged();这样才能实现通知观察者的效果。

实现两个观察者
新闻观察者
public class ConsumerPaperObserver implements Observer {
    private Observable o;
    public void update(Observable o, Object arg) {
        this.o = o;
        if (o instanceof PaperObservable){
            System.out.println("民生类,今天订阅的新内容是:"+o.toString());
        }
    }
}
民生类新闻观察者
public class NewsPaperObserver implements Observer {
    private Observable o;
    public void update(Observable o, Object arg) {
        this.o = o;
        if (o instanceof PaperObservable){
            System.out.println("新闻类,今天订阅的新内容是:"+o.toString());
        }
    }
}
打印结果
public class App 
{
    public static void main( String[] args ) {
        PaperObservable paperObservable = new PaperObservable();
        //更新今天的主题内容
        paperObservable.setTodayNews("2017-09-07","lzl修复100+bug","程序员一天内努力修复100+bug");
        //添加订阅者
        NewsPaperObserver newsPaperObserver = new NewsPaperObserver();
        ConsumerPaperObserver consumerPaperObserver = new ConsumerPaperObserver();
        paperObservable.addObserver(newsPaperObserver);
        paperObservable.addObserver(consumerPaperObserver);
        paperObservable.todayNewsChange();

    }
}
民生类,今天订阅的新内容是:PaperObservable{date='2017-09-07', title='lzl修复100+bug', content='程序员一天内努力修复100+bug'}
新闻类,今天订阅的新内容是:PaperObservable{date='2017-09-07', title='lzl修复100+bug', content='程序员一天内努力修复100+bug'}

看看java设计模式的源码

这里写图片描述
其实java只提供了两个主要类Observable(主题)类和Observer(观察者)接口类。

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);
}
Observable的实现

有以下提供
* 线程安全的Observer对象集合。
* 添加、删除、通知观察者的方法

private boolean changed = false;
    private Vector<Observer> 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);
    }

    /**
    Object 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();
    }
   //当要通知观察者时候,调用
    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();
    }

注意 java的观察者模式没有按照严格的接口编程,而是使用了继承的方式。这样的扩展性不好,设计上没有弹性。我们可以模拟实现一个面向接口的观察者模式。

主题接口
public interface MyObserverble {
    /**
     * 删除观察者
     */
    void removeObserver(MyObserver myObserver);

    /**
     * 添加观察者
     * @param myObserver
     */
    void addObserver(MyObserver myObserver);

    /**
     * 通知观察者,某个
     * @param myObserver
     */
    void notifyObserver(MyObserver myObserver);

    /**
     * 通知所有的观察者
     */
    void notifyObserver();
}
实现
public class MyObserverbleImpl implements MyObserverble {
    private List<MyObserver> observers = null;

    public MyObserverbleImpl(){
        observers = new ArrayList<MyObserver>();
    }
    public void removeObserver(MyObserver myObserver) {
        observers.remove(myObserver);
    }

    public void addObserver(MyObserver myObserver) {
        observers.add(myObserver);
    }

    public void notifyObserver(MyObserver myObserver) {
        observers.get(observers.indexOf(myObserver)).update(this, myObserver);
    }

    public void notifyObserver() {
        for (MyObserver myObserver : observers){
            myObserver.update(this, myObserver);
        }
    }
}
主题类的实现
public class MyPaperObservable extends MyObserverbleImpl{
    private String date;
    private String title;
    private String content;

    public void todayNewsChange(){
       super.notifyObserver();
    }
    public void setTodayNews(String date,String title,String content){
        this.date = date;
        this.title = title;
        this.content = content;
    }

    @Override
    public String toString() {
        return "PaperObservable{" +
                "date='" + date + '\'' +
                ", title='" + title + '\'' +
                ", content='" + content + '\'' +
                '}';
    }
}

这里观察者接口和类就不列举了,和Observer类没有说明区别。
只是改写了主题类,将其设计为接口,这样不同的主题可以实现接口。灵活性比较高
不过类的创建还是面向对象创建的。

public class ObserverbleMain
{
    public static void main( String[] args ) {
        MyPaperObservable paperObservable =  new MyPaperObservable();
        //更新今天的主题内容
        paperObservable.setTodayNews("2017-09-0909","lzl修复100+bug","程序员一天内努力修复100+bug");
        //添加订阅者
        MyNewsPaperObserver newsPaperObserver = new MyNewsPaperObserver();
        ConsumerPaperObserver consumerPaperObserver = new ConsumerPaperObserver();
        paperObservable.addObserver(newsPaperObserver);
        paperObservable.addObserver(consumerPaperObserver);
        paperObservable.todayNewsChange();

    }
}

uml图如下
这里写图片描述

详细的代码可以从github上下载到
https://github.com/hpulzl/lzl_workspace/tree/master/gof_demo

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值