观察者模式

举报
神的孩子在歌唱 发表于 2024/10/30 09:21:54 2024/10/30
【摘要】 观察者模式前言这是我在这个网站整理的笔记,有错误的地方请指出,关注我,接下来还会持续更新。作者:神的孩子都在歌唱一.简介百度百科: 观察者模式是一种对象行为模式。又被称为发布-订阅(Publish/Subscribe)模式, 它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。在观察者模式中,主体是通知的发布者,它发出通知时并不需要知道谁...

观察者模式

前言

这是我在这个网站整理的笔记,有错误的地方请指出,关注我,接下来还会持续更新。

作者:神的孩子都在歌唱

一.简介


百度百科: 观察者模式是一种对象行为模式。又被称为发布-订阅(Publish/Subscribe)模式, 它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。在观察者模式中,主体是通知的发布者,它发出通知时并不需要知道谁是它的观察者,可以有任意数目的观察者订阅并接收通知。观察者模式不仅被广泛应用于软件界面元素之间的交互,在业务对象之间的交互、权限管理等方面也有广泛的应用。


个人理解: 这个模式在日常开发中很常见,比如a服务想要b服务磁盘满的时候通知它,那么它只需要把自己的grpc或者http接口给到b服务,b服务订阅后,如果磁盘满了就调用a服务注册的接口 通知。


在观察者模式中有如下角色:

  • 抽象主题(Subject):它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。

  • 具体主题(Concrete Subject):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。

  • 抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。

  • 具体观察者(Concrete Observer):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。



二. 案例

我将实现一个简单的主题(Subject)观察者(Observer)可以注册到该主题。每当有新消息发布到主题时,所有注册观察者都会收到通知,并且他们可以使用该消息。

image-20240606162329977.png

这里是基本Subject接口,它定义了任何具体主题要实现的接口方法。


2.1 抽象主题(Subject)

/**
 * @author chenyunzhi
 * @date 2024/6/5 17:13
 * @Description 主题
 */
public interface Subject {
​
    /**
     * 注册观察者
     */
    void register(Observer observer);
​
    /**
     * 取消观察者
     */
    void unregister(Observer observer);
​
    /**
     * 通知观察者消息有更新
     */
    void notifyObservers();
​
}


2.2 具体主题(Concrete Subject)

/**
 * @author chenyunzhi
 * @date 2024/6/5 17:21
 * @Description 实现主题
 */
public class SubjectImpl implements Subject{
​
    /**
     * 同步锁
     */
    private final Object SUB= new Object();
​
    /**
     * 存储注册的观察者
     */
    private final List<Observer> observers = new ArrayList<>();
​
    /**
     * 要通知的消息
     */
    private String message;
​
    /**
     * 防止 notifyObservers方法被外部调用发送错误通知
     */
    private boolean flag;
​
    @Override
    public void register(Observer observer) {
        if (observer != null) {
            synchronized (SUB) {
                // 如果不在就存储
                if (!observers.contains(observer)) {
                    observers.add(observer);
                }
            }
        }
    }
​
    @Override
    public void unregister(Observer observer) {
        if (observer != null) {
            synchronized (SUB) {
                observers.remove(observer);
            }
        }
    }
​
    @Override
    public void notifyObservers() {
​
        List<Observer> objects = new ArrayList<>();
        //使用同步方法确保通知仅发送给新消息前注册的观察者
        synchronized (SUB) {
            if (!flag) {
                return;
            }
            objects = this.observers;
            this.flag = false;
        }
        for (Observer observer:objects) {
            // 通知观察者,有消息更新
            observer.update(this.message);
        }
​
    }
​
    /**
     * 自定义一个消息变更方法方便测试
     */
    public void updateMessage(String message) {
        System.out.println("消息有变更,通知注册的观察者");
        this.message = message;
        this.flag = true;
        // 通知
        notifyObservers();
    }
}


2.3 抽象观察者(Observer)


/**
 * @author chenyunzhi
 * @date 2024/6/5 17:14
 * @Description 观察者类
 */
public interface Observer {
​
    /**
     * 定义要更新的方法,由主题调用
     */
    void update(String msg);
}


2.4 具体观察者(Concrete Observer)

/**
 * @author chenyunzhi
 * @date 2024/6/5 17:59
 * @Description 观察者实现类
 */
public class ObserverImpl implements Observer{
​
    /**
     * 观察者名称
     */
    private final String observerName;
    public ObserverImpl(String name) {
        this.observerName = name;
    }
​
    @Override
    public void update(String msg) {
        System.out.println(observerName + "接收到消息:" + msg);
    }
}



2.5 测试

/**
 * @author chenyunzhi
 * @date 2024/6/6 14:57
 * @Description 观察者模式测试
 */
public class ObserverPatternTest {
    public static void main(String[] args) {
        // 创建观察者并注册到主题
        SubjectImpl subject = new SubjectImpl();
        subject.register(new ObserverImpl("观察者1"));
        subject.register(new ObserverImpl("观察者2"));
        subject.register(new ObserverImpl("观察者3"));
​
        // 测试 更新消息
        subject.updateMessage("订阅的主题有消息更新了");
​
    }
}


image-20240606162024139.png


三. 结论

3.1 优缺点

1.优点:

  • 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。

  • 被观察者发送通知,所有注册的观察者都会收到信息【可以实现广播机制】

2.缺点:

  • 如果观察者非常多的话,那么所有的观察者收到被观察者发送的通知会耗时

  • 如果被观察者有循环依赖的话,那么被观察者发送通知会使观察者循环调用,会导致系统崩溃


3.2 使用场景

  • 对象间存在一对多关系,一个对象的状态发生改变会影响其他对象。

  • 当一个抽象模型有两个方面,其中一个方面依赖于另一方面时。


作者:神的孩子都在歌唱

本人博客:https://blog.csdn.net/weixin_46654114

转载说明:务必注明来源,附带本人博客连接

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。