设计模式:观察者模式与发布-订阅模式


前言

这里记录笔者对观察者模式的学习

一、观察者模式介绍

要想学习观察者模式,我们需要清楚什么是观察者模式,下面来看一番定义

观察者模式 在软件设计中是一个对象,维护一个依赖列表,当任何状态发生改变自动通知它们。

以上的定义似乎难以让人直接理解观察者模式,下面来看一个具体形象的例子

我们假设你在寻找一份工作,你又恰好对希望公司很感兴趣,于是乎你联系他们的HR,告诉HR有任何职位空缺联系你。
同时还有几个候选人也对你一样对上方公司感兴趣。所以职位空缺大家都会被通知,如果你回应了他们的通知,他们就会联系你面试。
在上方的例子中,公司就是Subject,用来维护Observers(候选人),为某些Event(职位空缺)来Notify观察者

二、观察者模式实现

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

关键字

  • Observable:即被观察者,也可以被叫做主题(Subject)是被观察的对象。通常有注册方法(Register),取消注册方法(remove)和通知方法(notify)。
  • Observer,即观察者,可以接收到主题的更新。当对某个主题感兴趣的时候需要注册自己,在不需要接收更新时进行注销操作。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
import  ssl
ssl._create_default_https_context = ssl._create_unverified_context

具体实现

这里介绍一个案例用Java进行观察者模式的原生实现

这里NewProvider作为对于报社的抽象,每隔两秒钟向用户发送报纸;User作为用户的抽象,可以收到报纸。NewsModel作为对报纸本身的抽象

/**
 * 被观察者接口定义
 */
public interface MyObserverable {

    void register(MyObserver myObserver);

    void remove(MyObserver myObserver);

    void send(NewsModel model);

}
/**
 * 观察者接口定义
 */
public interface MyObserver {

    void receive(NewsModel model);

}
/**
 * 对于报社的抽象,实现了被观察者接口,每隔2s发送一次报纸
 */
public class NewsProvider implements MyObserverable {
    private static final long DELAY = 2 * 1000;
    private List mObservers; //我们用一个List来维护所有的观察者对象

    public NewsProvider() {
        mObservers = new ArrayList<>();
        generateNews();
    }

    /**
     * 模拟产生新闻,每个2s发送一次
     */
    private void generateNews() {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            int titleCount = 1;
            int contentCount = 1;

            @Override
            public void run() {
                send(new NewsModel("title:" + titleCount++, "content:" + contentCount++));
            }
        }, DELAY, 1000);
    }

    @Override
    public void register(MyObserver myObserver) {
        if (myObserver == null)
            return;
        synchronized (this) {
            if (!mObservers.contains(myObserver))
                mObservers.add(myObserver);
        }
    }

    @Override
    public synchronized void remove(MyObserver myObserver) {
        mObservers.remove(myObserver);
    }

    @Override
    public void send(NewsModel model) {
        for (MyObserver observer : mObservers) {
            observer.receive(model);
        }
    }
}

这里对报社的抽象尽量使用单例模式进行实现

/**
 * 对于用户的抽象
 */
public class User implements MyObserver {
    private String mName;

    public User(String name) {
        mName = name;
    }

    @Override
    public void receive(NewsModel model) {
        System.out.println(mName + " receive news:" + model.getTitle() + "  " + model.getContent());
    }
}
/**
 * 测试类
 */
public class Test {
    public static void main(String[] args) {

        NewsProvider provider = new NewsProvider();
        User user;
        for (int i = 0; i < 10; i++) {
            user = new User("user:"+i);
            provider.register(user);
        }

    }
}

2.JDK类实现简单观察者模式

其实在JDK的util包内Java为我们提供了一套观察者模式的实现,在使用的时候我们只需要继承ObservableObserver类即可,其实观察者模式十分简单,推荐阅读JDK的实现代码真心没有几行。此外在JDK的实现中还增加了一个布尔类型的changed域,通过设置这个变量来确定是否通知观察者。

来看上方的重构

public class NewsProvider extends Observable {
    private static final long DELAY = 2 * 1000;

    public NewsProvider() {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
           private int titleCount = 1;
           private int contentCount = 1;
            @Override
            public void run() {
                setChanged(); //调用setChagned方法,将changed域设置为true,这样才能通知到观察者们
                notifyObservers(new NewsModel("title:" + titleCount++, "content:" + contentCount++));
            }
        }, DELAY, 1000);
    }
}
public class User implements Observer {
    private String mName;

    public User(String name) {
        mName = name;
    }

    @Override
    public void update(Observable observable, Object data) {
        NewsModel model = (NewsModel) data;
        System.out.println(mName + " receive news:" + model.getTitle() + "  " + model.getContent());
    }
}

三、观察者模式与发布-订阅模式的不同

经常会被提及的问题是,观察者模式和发布-订阅模式有什么区别

在观察者模式中的Subject就像一个发布者==(Publisher),观察者(Observer)就是订阅者(Subscriber)。Subject通知观察者(Observer)就像发布者(Publisher)通知他的订阅者(Subscriber)。所以很多书和文章使用发布-订阅概念来解释观察者设计模式。但是这里还有另外一个流行的模式叫做发布-订阅设计模式==。

在发布-订阅模式,消息的发送方,叫做发布者(publishers),消息不会直接发送给特定的接收者,叫做订阅者(Subscriber)。

意思就是发布者和订阅者不知道对方的存在。需要一个第三方组件,叫做信息中介,它将订阅者和发布者串联起来,它过滤和分配所有输入的消息。换句话说,发布-订阅模式用来处理不同系统组件的信息交流,即使这些组件不知道对方的存在。

我们对观察者模式和发布-订阅模式的区别进行总结

  • 在观察者模式中,观察者是知道Subject的,Subject记录了所有的观察者。然而,在发布订阅模式中,发布者和订阅者不知道对方的存在。它们只有通过消息代理进行通信。
  • 在发布订阅模式中,组件是松散耦合的,正好和观察者模式相反。
  • 观察者模式大多数时候是同步的,比如当事件触发,Subject就会去调用观察者的方法。而发布-订阅模式大多数时候是异步的(使用消息队列)。
  • 观察者模式需要在单个应用程序地址空间中实现,而发布-订阅更像交叉应用模式。

总结

以上是笔者对于观察者模式和发布-订阅模式的总结

参考博客
观察者模式的 Java 实现及应用
观察者模式 vs 发布-订阅模式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值