观察者模式

GOF概括:定义对象间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都得到通知并被自动更新。

“观察者模式” 可以引申出非常多的知识点:“发布-订阅者模式”、“消息队列”……你几乎能在任何项目见到观察者模式的应用。
观察者模式是非常重要的一个设计模式,几乎会伴随着程序员走过整个职业生涯。

简单地说,就是一个对象,做了某件事,另一个对象要接着做点啥?

往大了说,卫星拍了一张照,新闻上你可能看到,天气系统,也可能会用到(不同系统之间存在消息订阅);
往小了说,就比如你 update 一条数据,日志系统要记录你的操作(一个代码模块内部也会有这种需求)。

简单案例

推送场景

这种代码结构非常常见,基本是要求背诵的。
一下子就能想到的,就是各种点击事件,例如:xxxClickListener(Event e)。

import java.util.ArrayList;
import java.util.List;

interface Observer{
    void onAction(String action);
}

class Subject{
    // 观察者集合
    List<Observer> list = new ArrayList<>();

    public void run(){
        // do sth.
        
        // then
        notifyObserver("ok");
    }

    public void notifyObserver(String action){
        for(Observer observer: list){
            observer.onAction(action);
        }
    }
}
拉取场景

拉取模式与推送模式的区别是:收到消息之后,可以根据需求,拉取不同的数据。
这种写法,缩小了消息体的大小,按需拉取数据,代码解耦程度也更高一些。

当然,这并没有改变 “推送模式” 的本质,就比如下面代码,把 getMsg1() 放到另一个类,代码还是标准的推送模式。

说实话,对于 “拉取模式” 这个词,我是有些怀疑的,像是老师为了为难学生,自己创造出来的名词。
首先,代码本身就有点不伦不类的;而且,介绍 “观察者模式” 的文章,根本看不到 “拉取模式” 的内容。

不管具体怎样,不排除面试可能有人会这么问你,很多人都是这么学的,所以还是要掌握一下。

有些文章会用 http 协议举例,客户端需要去拉取后台的数据,但是很明显,后台状态发生变化,前端根本不会收到通知,这不符合 “观察者模式” 的定义。

import java.util.ArrayList;
import java.util.List;

class Observer{

    public void onAction(Subject action){
        System.out.println(action.getMsg1());
    }
}

class Subject{
    List<Observer> list = new ArrayList<>();

    public void run(){
        // do sth.
        notifyObserver();
    }

    public String getMsg1(){
        return "message1";
    }

    public String getMsg2(){
        return "message2";
    }

    public void notifyObserver(){
        for(Observer observer: list){
            observer.onAction(this);
        }
    }
}

JDK标准实现

JDK 的 java.util 包提供了标准接口,可能整个职业生涯都用不上,
当然,多少要了解一些,因为面试可能会被提问。

实在不想了解,可以这么解释:因为 java 是单继承,Observable 的设计注定不会太实用;
业务上,需求往往十分复杂,使用 Observable 这样一个不常用、又很复杂的类,可能会增加维护负担。

一些文章认为,JDK 的实现是拉取模式,因为 update() 第一个参数是 Observable,
但是实际上,一个观察者,可以侦听很多消息,Observable 本身就是必要的,需要用它确定消息来源。

import java.util.Observable;
import java.util.Observer;

class Obs implements Observer {

    @Override
    public void update(Observable o, Object arg) {
        System.out.println(o);
        System.out.println(arg);
    }
}

class Subject extends Observable{

    public void run(){
        // do sth.
        super.setChanged();
        super.notifyObservers("msg");
    }
}

public class Test2  {
    public static void main(String[] args) {
        Obs obs = new Obs();
        
        Subject subject = new Subject();
        subject.addObserver(obs);

        subject.run();
    }
}

posted on 2016-10-29 15:39  疯狂的妞妞  阅读(126)  评论(0编辑  收藏  举报

导航