设计模式——观察者模式

|▌冷眼眸甩不掉的悲伤 提交于 2019-11-26 17:55:14

观察者模式

定义

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

类图

例子

假设由这样一个例子,大家都比较关注房价,所以关注了一个网站,利用rss订阅。当有新的动态更新时,所有订阅的用户就会收到最新的消息。

定义主题及其实现House Site

package com.gitlearning.hanldegit.patterns.observe.first;

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

/**
 * 房子站点
 */
public class HouseSite implements Subject{

    private List<Subscriber> observers;

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

    @Override
    public void registerObserver(Subscriber subscriber) {
        observers.add(subscriber);
    }

    @Override
    public void removeObserver(Subscriber subscriber) {
        observers.remove(subscriber);
    }

    @Override
    public void publishMessage(String message) {
        observers.forEach(observer -> observer.updateMessage(message));
    }

}

interface Subject {
    void registerObserver(Subscriber subscriber);
    void removeObserver(Subscriber subscriber);
    void publishMessage(String message);
}

定义订阅者及其实现:

package com.gitlearning.hanldegit.patterns.observe.first;

public interface Subscriber {

    void updateMessage(String message);
}

class Person implements Subscriber{
    String name;

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

    @Override
    public void updateMessage(String message) {
        System.err.println(name + "收到了最新消息: " + message);
    }
}

测试程序如下:

package com.gitlearning.hanldegit.patterns.observe.first;

import org.junit.jupiter.api.Test;

public class TestObserver {
    @Test
    void test() {
        Subject houseSite = new HouseSite();
        Person zhangsan = new Person("张三");
        Person lisi = new Person("李四");
        houseSite.registerObserver(zhangsan);
        houseSite.registerObserver(lisi);
        houseSite.publishMessage("今日涨价房源100套,降价房源888套。");

        houseSite.removeObserver(lisi);
        houseSite.publishMessage("今日有事,网站暂停更新");
    }
}

输出消息为:

张三收到了最新消息: 今日涨价房源100套,降价房源888套。
李四收到了最新消息: 今日涨价房源100套,降价房源888套。
张三收到了最新消息: 今日有事,网站暂停更新

其实JAVA本身就提供了对观察者模式的支持,主题类Observable

package com.gitlearning.hanldegit.patterns.observe.userInternal;

import java.util.Observable;

public class HouseSite extends Observable {
    void publishEvent(String message) {
        setChanged();
        notifyObservers(message);
    }
}

观察者Observer:

package com.gitlearning.hanldegit.patterns.observe.userInternal;

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

public class Person implements Observer {
    String name;

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

    @Override
    public void update(Observable o, Object arg) {
        System.err.println(name + "收到了最新消息: " + arg);
    }
}

测试代码:

package com.gitlearning.hanldegit.patterns.observe.userInternal;

import org.junit.jupiter.api.Test;

import java.util.Observer;

public class TestObserverWithInternal {
    @Test
    void test() {
        HouseSite site = new HouseSite();
        Observer zhangsan = new Person("张三");
        Observer lisi = new Person("李四");
        site.addObserver(zhangsan);
        site.addObserver(lisi);
        site.publishEvent("今日最新消息, 首套房利率上浮25%");

        site.deleteObserver(zhangsan);
        site.publishEvent("离岸人民币汇率破7!");
    }
}

结果:

李四收到了最新消息: 今日最新消息, 首套房利率上浮25%
张三收到了最新消息: 今日最新消息, 首套房利率上浮25%
李四收到了最新消息: 离岸人民币汇率破7!

这里需要注意一点,需要在Observable里设置changed状态,要不然无法调用update方法。

使用

Spring的ApplicationEvent继承自jdk中的EventObject,ApplicationListener继承自EventListener。

发布事件的时候触发监听器的onApplicationEvent方法,那触发的方法就在于ApplicationContext中。例如AbstractApplication的refresh()方法里的registerListeners(),通过ApplicationEventMulticaster广播出去,触发监听器的onApplicationEvent方法。

顺便讲一下,ApplicationEventPublisher有publishEvent方法,其实也是通过调用MultiCaster来实现的。

其他

  1. 观察者模式定义了对象之间一对多的关系
  2. 主题(也就是可观察者)用一个共同的接口来更新观察者。
  3. 使用观察者模式,可以采用推或者拉的模式
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!