观察者模式

观察者模式–浅谈


在说观察者模式之前,我们先来说下设计模式的几大原则:
单一职责原则
开放关闭原则
里氏代换原则
依赖倒转原则
接口隔离法则
迪米特法则

观察者模式
又称发布–订阅模式(有时又称为模型(Model)-视图(View)模式、源-收听者(Listener)模式或从属者模式)。观察者模式完美的将观察者和被观察者的对象分离开,举个例子,用户界面作为观察者,业务数据作为被观察者,两者之间存在“观察”的逻辑,用户界面观察业务数据的变化,当被观察者(业务数据)发生变化时,观察者(用户界面)就会观察到到变化,并作出相应的响应。

实现
实现观察者模式的时候要注意,观察者和被观察对象之间的互动关系不能体现成类之间的直接调用,否则就将使观察者和被观察对象之间紧密的耦合起来,从根本上违反面向对象的设计的原则。无论是观察者“观察”观察对象,还是被观察者将自己的改变“通知”观察者,都不应该直接调用。
以上,我们可以看出,观察者模式主要用于解耦,将观察者和被观察者解耦,让两者之间没有依赖或者依赖关系很小。

应用
Android四大组件之一的BroadcastReceiver,实际上也是一个典型的观察者模式,通过sendBroadcast发送广播时候,只有注册了相应的IntentFilter的BroadcastReceiver对象才会收到这条广播消息,进而做出响应。
另外,现在比较流行的第三方框架很多也是用的观察者模式,例如EventBus、RxJava、RxAndroid、otto等等。在这里就不拿其中一个作为例子解析。

角色说明
Subject(抽象主题):又叫抽象被观察者,把所有观察者对象的引用保存到一个集合里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
ConcreteSubject(具体主题):又叫具体被观察者,将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
Observer (抽象观察者):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
ConcrereObserver(具体观察者):实现抽象观察者定义的更新接口,当得到主题更改通知时更新自身的状态。

具体实现例子
让我们用父亲通知儿子做事的例子来说明
1、创建抽象观察者—Observer
定义一个接到通知的更新方法,即儿子们接到通知后的反应

public interface Observer {
    public void updata(String msg);
}

2、创建具体观察着(即儿子们)—ConcrereObserver

public class SonSeaObserver implements Observer {

    private String name;

    public SonSea(String name) {
        this.name = name;
    }

    @Override
    public void updata(String msg) {
        System.out.println(name+"收到了消息:"+msg+"后开始傲娇拒绝");
    }
}
public class SonZhenObserver  implements Observer {

    private String name;

    public SonZhen(String name) {
        this.name = name;
    }

    @Override
    public void updata(String msg) {
        System.out.println(name+"收到了消息:"+msg+"屁颠屁颠照做了");
    }
}

3、创建抽象主题----Subject
即抽象被观察者,定义添加、删除、通知等方法

public interface Observable {

    void add(Observer observer);

    void remove(Observer observer);

    void notify(String msg);
}

4、创建具体主题—ConcreteSubject
即具体被观察者(父亲),发布通知

public class FatherObservable  implements Observable {

    private List<Observer> sonList = new ArrayList<>();

    @Override
    public void add(Observer observer) {
        sonList.add(observer);
    }

    @Override
    public void remove(Observer observer) {
        sonList.remove(observer);
    }

    @Override
    public void notify(String msg) {
        for (Observer observer : sonList){
            observer.updata(msg);
        }
    }
}   

5、具体测试

private void testObserver(){
        Observable fatherOb = new FatherOb();
        SonSea sonSea = new SonSea("海海");
        SonZhen sonZhen = new SonZhen("大正");

        fatherOb.add(sonSea);
        fatherOb.add(sonZhen);

        fatherOb.notify("去扑街啦");
    }

6、理解
实际上,JDK内部也内置了Observable(抽象被观察者),Observer(抽象观察者)这两个类,我们也可以直接拿来用,其代码如下:

public interface Observer {//(抽象观察者
    //只定义了一个update方法
    void update(Observable o, Object arg);
}

public class Observable {//抽象被观察者
    private boolean changed = false;//定义改变状态,默认为false
    private final ArrayList<Observer> observers;//定义一个观察者list

    public Observable() {//构造函数,初始化一个观察者list来保存观察者
        observers = new ArrayList<>();
    }
    //添加观察者,带同步字段的,所以是线程安全的
    public synchronized void addObserver(Observer o) {
        if (o == null)
            throw new NullPointerException();
        if (!observers.contains(o)) {
            observers.add(o);
        }
    }

    //删除观察者
    public synchronized void deleteObserver(Observer o) {
        observers.remove(o);
    }

    //通知所以观察者,无参数
    public void notifyObservers() {
        notifyObservers(null);
    }

     //通知所有观察者,带参数
    public void notifyObservers(Object arg) {

        Observer[] arrLocal;
        //加synchronized字段,保证多线程下操作没有问题
        synchronized (this) {
            if (!hasChanged())//这里做了是否发生改变的判断,是为了防止出现无意义的更新
                return;

            arrLocal = observers.toArray(new Observer[observers.size()]);//ArrayList转换成一个临时的数组,这样就防止了通知,添加,移除同时发生可能导致的异常
            clearChanged();///清除改变状态,设置为false
        }
        //遍历逐一通知
        for (int i = arrLocal.length-1; i>=0; i--)
            arrLocal[i].update(this, arg);
    }

    //清楚所有观察者
    public synchronized void deleteObservers() {
        observers.clear();
    }

    //设置被观察者为改变状态,设置为true
    protected synchronized void setChanged() {
        changed = true;
    }

    //清除改变状态,设置为false
    protected synchronized void clearChanged() {
        changed = false;
    }

    //返回当前的改变状态
    public synchronized boolean hasChanged() {
        return changed;
    }

    //观察者数量
    public synchronized int countObservers() {
        return observers.size();
    }
}

优点

  • 解除观察者与主题之间的耦合。让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。
  • 易于扩展,对同一主题新增观察者时无需修改原有代码。

缺点

  • 依赖关系并未完全解除,抽象主题仍然依赖抽象观察者。
  • 使用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且在Java中消息的通知一般是顺序执行,那么一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步实现。
  • 可能会引起多余的数据通知。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值