JAVA设计模式——观察者模式(Observer Pattern)

概述

考虑到一个现实需求,实现微信的订阅通知功能,即某某公众号发布了一个消息,那么所有订阅了该公众号消息订阅的使用者都会得到这个消息的通知。如何实现?下意识脑中想到了轮询,订阅者并不知道什么时候公众号会发布新消息,那么我们可以让订阅的人每隔一段时间去检查一下公众号的状态,看看有没有发布新的消息。但是现实中真的是这样实现的吗?这样做会有以下的缺陷:

1、消耗资源去主动检查公众号状态。

2、无法及时的得到消息订阅提醒。看似只要轮询的间隔足够小,订阅者就能够及时的得到订阅消息。轮询时间间隔越小,单位时间消耗资源去检查公众号状态的次数就会变多;轮询时间间隔越大,我们就无法及时的得到新消息提醒。

3、采取这种方式,每次有新的客户订阅消息,我们都需要往发布者代码中增加该客户(想一下,这种模式下公众号必须保存所有的订阅者可能是以List或者其他形式存储),每次增加订阅者都需要改一下发布者的代码。

基于类似以上的需求,观察者模式(也叫发布订阅模式)被提出,它是对多个对象之间定义了一对多的依赖,即一个对象发生了变化,依赖它的对象都会得到响应的提醒并采取相应的操作。即发布者发布信息,订阅者获取信息,订阅了相关消息的就能收到相应的消息,没有订阅就不能收到。

模式中的角色

1、抽象的被观察者:抽象的行为有,添加、删除观察者和在状态发生改变时通知观察者

2、抽象的观察者:抽象的行为主要是收到被观察者通知后执行相应的操作,比如订阅消息后,收到公众号通知有新消息,则展示新消息。

3、具体的被观察者:

4、具体的观察者:

应用举例

就拿概述中的需求而言,做个简单的Demo,有一个公众号实例,若干个订阅者实例,现在要实现的功能就是公众号能够发布新的消息,同时对于每一个订阅者,能够订阅和取消订阅公众号,同时在公众号发布新消息时能够及时展示新消息。

public interface Subject {

    public void registerObserver(Observer o);

    public void removeObserver(Observer o);

    public void notifyObservers();

}
public interface Observer {

    public void update(String newmessage);

}
import java.util.ArrayList;

public class Subscription implements Subject{
    private ArrayList observers;//公众号保存订阅者
    private String newMessage;//公众号发布的新消息,现实中应该是用集合类或者其他技术实现,毕竟还需要保存历史消息,此处就采用字符串测试功能

    public Subscription(){
        this.observers = new ArrayList();
    }
    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
    }

    @Override
    public void removeObserver(Observer o) {
        int i = observers.indexOf(o);
        observers.remove(i);
    }

    @Override
    public void notifyObservers() {
        for(int i =0;i<observers.size();i++){
            Observer observer = (Observer) observers.get(i);
            observer.update(newMessage);
        }
    }

    public void updateNewMessage(String newMessage){
        this.newMessage = newMessage;
        notifyObservers();
    }
}
public class Subscriber implements Observer{
    private String name;
    private String newMessage;

    public Subscriber(String name,Subject subscription){
        this.name = name;
        subscription.registerObserver(this);
    }

    @Override
    public void update(String newmessage) {
        this.newMessage = newmessage;
        show();
    }

    private void show() {
        System.out.println(name+"收到新消息:"+newMessage);
    }
}
public class Test {
    public static void main(String[] args) throws InterruptedException {
        Subscription subscription_1 =
                new Subscription();
        Subscriber subscriber_1 = new Subscriber("张三",subscription_1);

        Subscriber subscriber_2 = new Subscriber("李四",subscription_1);

        Subscriber subscriber_3 = new Subscriber("王五",subscription_1);

        subscription_1.updateNewMessage("小米拟投资77.6亿在深圳设立国际总部");

        System.out.println("------------------------------------------------");

        Thread.sleep(1000);

        subscription_1.updateNewMessage("麦当劳中国将停用塑料吸管");

    }
}

执行结果如下:

可以看到在订阅了消息之后,订阅者不用一直关注公众号是否发布了新消息,并且在公众号发布新消息后,能够及时的接收到新消息。

总结

观察代码,我们在代码中做了什么?我们声明了两个接口,分别交给观察者和被观察者继承。在被观察者的代码中,我们只是保存了一个抽象观察者者的集合;在观察者的代码中,我们只是在构造方法中获取了将被观察者作为抽象被观察者的引用,这么做的目的仅仅是将我们注册为被观察者的观察者,我们也可以在观察者中单独写个方法用于将自己注册为观察者,毕竟一个人也可以订阅多个公众号嘛!
通过抽象成接口的方式,使得观察者和被观察者只需要知道自己需要观察什么以及提醒观察者,从而保证了观察者和被观察者代码中其他部分的独立,起到解耦合的作用(我是这么理解的,可能后面也会有新的认识),观察者模式(发布订阅模式)通过这种方式让观察者不需要花费开销在盯着被观察者的状态上,而是让被观察者一发生改变便主动提醒观察者,这样的逻辑开销更低,同时得到反馈也更及时。
展开阅读全文

Windows版YOLOv4目标检测实战:训练自己的数据集

04-26
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值