设计模式——观察者模式

Posted studentytj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式——观察者模式相关的知识,希望对你有一定的参考价值。

观察者模式

定义

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

类图

技术图片

例子

假设由这样一个例子,大家都比较关注房价,所以关注了一个网站,利用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. 使用观察者模式,可以采用推或者拉的模式

以上是关于设计模式——观察者模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式之观察者模式

观察者模式是啥

[设计模式]观察者模式与订阅模式

设计模式-行为型模式-观察者模式

常用设计模式-----观察者模式

设计模式之行为型模式