设计模式之观察者模式

观察者模式是面向对象编程中较为常见的一种设计模式,观察者模式又称为订阅发布模式,可能大家对观察者模式从字面上可以理解,但是对代码层面上不太清楚如何实现,通过本文学习,相信你会对观察者有一个更清晰的了解。

定义

观察者模式:定义了对象之间的一对多依赖,当一个对象改变状态时,它的所有依赖者都会受到通知并自动更新。

从上面的定义描述中,我们可以了解到观察者模式有两个重点:观察者、被观察者。我们从生活中的例子来理解下。我们去报社订阅报纸,报社与用户之间就是一对多依赖,用户可以在报社订阅(register)报纸,报社可以把最新的报纸发到用户手上(notify),用户就会收到最新的报纸。用户不再需要的时候可以取消订阅(remove)。

从现在热门Library有EventBus,RxJava的实现都是基于观察者模式思想,到时有人问起时,你会从使用层面到源码层面都能说清他们的时候。另外Android的点击监听事件OnClickListener都是使用了观察者模式。

从字面意思上理解完之后,我们看一下UML类图,从类图方面来理解观察者模式。

UML类图

这里写图片描述

我们分析一下上图:

Observerable:被观察者接口,规定了三个方法,分别是registerObserver():表示将观察者注册到被观察者中,即“订阅”;removeObserver():表示将观察者从被观察者中移除,即“取消订阅”;notifyObservers()当被观察者的属性发生变化时候,这个方法将被调用,通知所有已经订阅注册的观察者。

ConcreteObserverable:被观察者,实现Observerable接口,在对上面的方法实现,同时有一个List集合,用保存注册的观察者,等通知观察者的时候遍历该集合。

Observer:观察者接口,定义update()方法,当被观察者通知观察者时候,观察者的update()方法将被回调。

ConcreteObserver:观察者,实现了update()方法。

从UML类图中,我们了解了观察者模式的实现过程,接下来我们从代码来进一步理解。

代码实现

被观察者接口:

interface Observerable {
    void registerObserverable(Observer o);

    void removeObserverable(Observer o);

    void notifyObserverable();
}

观察者接口:

interface Observer {
    void update(NewsPaper newspager);
}

新建报社类,实现被观察者接口:

public class Company implements Observerable {
    private List<Observer> observers;
    private NewsPaper mNewsPaper;

    public Company() {
        observers = new ArrayList<>();
    }

    @Override
    public void registerObserverable(Observer o) {
        // TODO Auto-generated method stub
        if (null == o)
            return;
        observers.add(o);
    }

    @Override
    public void removeObserverable(Observer o) {
        // TODO Auto-generated method stub
        if (null == o || observers.size() <= 0)
            return;
        observers.remove(o);
    }

    @Override
    public void notifyObserverable() {
        // TODO Auto-generated method stub
        for (int i = 0; i < observers.size(); i++) {
            Observer observer = observers.get(i);
            observer.update(mNewsPaper);
        }
    }

    public void setNewsPaperBean(NewsPaper newsPaper) {
        this.mNewsPaper = newsPaper;
        notifyObserverable();
    }
}

新建用户类,实现观察者接口:

public class User implements Observer {
    private String mUserId;
    private NewsPaper mNewsPager;

    public User(String id) {
        mUserId = id;
    }

    @Override
    public void update(NewsPaper newspager) {
        // TODO Auto-generated method stub
        mNewsPager = newspager;
        buy();
    }

    private void buy() {
        System.out.println("用户" + mUserId + "获得报纸" + mNewsPager.getMessage());
    }
}

观察者类与被观察者类我们都准备好了,接下来我们看一下客户端如何实现:

public class JavaDemo {

    public static void main(String[] args) {
        //创建被观察者实例
        Company company = new Company();
        //创建三个观察者用户实例
        Observer customerA = new User("A");
        Observer customerB = new User("B");
        Observer customerC = new User("C");
        //只有A、B用户进行了注册订阅
        company.registerObserverable(customerA);
        company.registerObserverable(customerB);
        //被观察者报社公司更新了新的报纸,通过订阅了的用户观察者
        company.setNewsPaperBean(new NewsPaper("羊城晚报"));
    }

}

打印结果:

用户A获得报纸羊城晚报
用户B获得报纸羊城晚报

从上面的例子中,我们看到出,这其实就是我们平时用的接口回调吗?甲乙两个对象,乙方持有甲方对象,在一定情况下,乙方用甲对象调用甲方方法。实现了回调方法。的确非常相似,但是我们的观察者模式是一对多的依赖。通过我们这里的观察者模式的了解,我们在学习EventBus和Retrofit的时候相信会更加易入手。

Java内置观察者模式

上面的都是根据我们的需要来实现观察者模式的,然而Java中,也为我们提供了Observerable类和Observer接口。我们看一下代码是如何实现:

新建被观察者,继承Observable:

public class Company extends Observable {
    private NewsPaper newsPaper;

    public void setNewsPaperBean(NewsPaper newsPaper) {
        this.newsPaper = newsPaper;
        setChanged();
        notifyObservers();
    }

    public NewsPaper getNewsPaper() {
        return newsPaper;
    }

    public void setNewsPaper(NewsPaper newsPaper) {
        this.newsPaper = newsPaper;
    }

}

新建观察者,实现Observer:

public class User implements Observer {
    private String mUserId;
    private NewsPaper mNewsPager;

    public User(String id) {
        mUserId = id;
    }

    @Override
    public void update(Observable o, Object arg1) {
        // TODO Auto-generated method stub
        if (o instanceof Company) {
            Company company = (Company) o;
            mNewsPager = company.getNewsPaper();
            buy();
        }
    }

    private void buy() {
        System.out.println("用户" + mUserId + "获得报纸" + mNewsPager.getMessage());
    }

}

客户端实现方式:

        Company company = new Company();

        User customerA = new User("A");
        User customerB = new User("B");
        User customerC = new User("C");

        company.addObserver(customerA);
        company.addObserver(customerB);
        company.addObserver(customerC);

        company.setNewsPaperBean(new NewsPaper("广州日报"));

打印结果:

用户C获得报纸广州日报
用户B获得报纸广州日报
用户A获得报纸广州日报

从结果我们可以看出,用Java内置提供的观察者模式,实现的结果与我们自己编写的结果是一致的。

相信大家从两个例子中,对观察者模式的理解已经更加清晰了。最后相信大家更加关注观察者模式的运用环境。比如我们有两个,一个对象依赖于另一个对象的变化而变化,这个时候我们可以单独将这两个对象抽象起来,抽象成接口的形式,然后就可以利用我们的观察者模式进行解耦。更更更直接的是,当一个对象发生变化时候,需要告知两个甚至多个对象时候,观察者模式就非常的适用这个场景了。

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值