观察者模式I

来源:互联网 发布:速达 sqlserver未安装 编辑:程序博客网 时间:2024/06/05 08:57

    • 什么是观察者模式
    • 代码描述
    • 何时使用观察者模式
    • 观察者模式给我们的思考
    • 之外的想法

什么是观察者模式?

这里写图片描述

  • 观察者模式定义了对象之间一(主题对象)对多(观察者)的一种依赖,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新

    我们认识观察者模式可以通过报社这个经典的例子:

  • 报社的业务是出版报纸

  • 向某家报社订阅报纸,只要他们有新报纸出版,就会给你送来,只要你是他们的订户,你就会一直收到新报纸
  • 当你不想再看报纸的时候,取消订阅,他们就不会再送新报纸来
  • 只要报社还在运营,就会一直有人向他们订阅报纸或取消订阅报纸

    报社视为主题对象,订户视为观察者,订阅行为视作观察者向主题对象注册,取消订阅行为视作观察者向主题对象取消注册

  • 正如下图所描述的一样
    这里写图片描述

代码描述

  • 先看一下后面代码的类文件结构
    这里写图片描述

为了直接体现观察者模式的思想,以下程序没有进行完善的异常判断和处理,省去了一些使程序更健壮的逻辑

  • 我们先看一下com.bd.subject包下的代码
    Subject.java这个就是主题接口
package com.bd.subject;import com.bd.observer.Observer;public interface Subject {    public void registerObserver(Observer o);    public void removeObserver(Observer o);    public void notifyObservers();}

然后是HeadHunter.java实现主题结构的”猎头类”(报社)

package com.bd.subject;import java.util.ArrayList;import com.bd.observer.Observer;public class HeadHunter implements Subject{    private ArrayList<Observer> observers = new ArrayList<>();    @Override    public void registerObserver(Observer o) {        observers.add(o);    }    @Override    public void removeObserver(Observer o) {        observers.remove(o);    }    @Override    public void notifyObservers() {        for (Observer o : observers) {            o.getNotification();        }    }    //控制是否有新消息,决定是否通知各个观察者    public void findWorks() {        notifyObservers();    }}
  • 然后我们看一下com.bd.observer包下的代码
    首先是Observer.java接口
package com.bd.observer;public interface Observer {    public void getNotification();}

然后是实现了这个接口的两个”Work”类(去报社订报纸的人)
WorkA.java

package com.bd.observer;public class WorkA implements Observer{    @Override    public void getNotification() {        System.out.println(getClass().getName() + " Get!");    }}

WorkB.java

package com.bd.observer;public class WorkB implements Observer{    @Override    public void getNotification() {        System.out.println(getClass().getName() + " Get!");    }}
  • 最后是测试类
package com.bd.main;import com.bd.observer.WorkA;import com.bd.observer.WorkB;import com.bd.subject.HeadHunter;public class Main {    public static void main(String[] args) {        HeadHunter headHunter = new HeadHunter();        WorkA workA = new WorkA();        WorkB workB = new WorkB();        // 谁想得到工作的消息,去注册        headHunter.registerObserver(workA);        headHunter.registerObserver(workB);        // 找到工作消息了,传递给各位观察者        headHunter.findWorks();    }}

细心的同学肯定会发现我写的和我画的类图不一样,因为按类图来说的话,WorkA和WorkB应该持有Subject的引用才对,但是实际代码实现时却没有持有,而是让headHunter主动的去注册相应的观察者,其实以上两种方式都可以实现,在我看来,他们主要有以下几点区别

  • 不让观察者持有主题的引用会降低他们之间的耦合,主题的状态你观察者没有权限知道,一切都由观察着掌控,我可以向你推送数据,完全取决于我内部的实现(上面的代码就没有实现主题向观察者推送数据的逻辑)
  • 但这样做存在一些缺点,就是局限性较大,灵活性不足,观察者是被通知和被传递数据,因为其内部没有主题的引用,所以无法得知主题的状态,同时就没有决定性的权限(意味着我们只能被动接受主题的控制,而不能自己做一些逻辑)
    如果你想push数据给观察者,很简单,因为主题操控着一切,你可以在notifyObservers()方法中传递数据对象给观察者,或者,观察者拥有主题的引用,可以去主动的pull数据

何时使用观察者模式

  • 当以下的情况满足一个或者多个时,都可以考虑是否可以使用观察者模式
    • 当一个抽象模型有两个方面,其中一个方面的操作依赖于另一个方面的变化
    • 当更改一个对象时,连带着需要更改其他对象,并且不知道到底有多少对象需要连带改变,并且连带对象有动态设置的需求
    • 当一个对象改变时必须要通知其他的对象,当他们之间必须保持松散耦合.

观察者模式给我们的思考

  • 观察者模式的核心在于松耦合,当两个对象之前松耦合,他们依然可以交互,但是不太清楚彼此的细节,主题只知道观察者实现了某个接口(Observer接口),它不需要知道观察者的具体类是谁,做了些什么或其他任何细节.任何时候我们都可以增加新的观察者,因为主题唯一依赖的东西是一个实现Observer接口的对象列表,所以我们可以随时增加观察者,并且,我们可以在运行时用新的观察者取代现有的观察者,主题不会有任何的影响,我们操作观察者时不需要去修改主题的代码,完全省去了兼容问题的麻烦,我们只需要将一个类实现Observer接口并注册为主题的观察者,就这么简单
  • 改变主题或观察者其中一方,并不会影响另一方,这就是松耦合的威力,只要他们之间的接口仍被遵循,我们就可以在这个基础上做任何事而不用担心闹出大乱子

之外的想法


  • 传统的观察者其实有个很局限的问题,就是观察者们很难做到动态的去接受特定消息,主题只要一推送,所有的观察者都得立刻做出反映,并且主题也没有办法去特定的操控某个特定的观察者,所以我们是不是能思考一种更加完善的解决方案,在保持最大化的松耦合的情况下,使观察者模式更具有灵活性?

业内已经有很多的解决方案,比如Android中的eventbus等等,我仔细研究和思考过后会给出一篇补充的文章来和大家分享我的感悟.

2 0