您现在的位置是:首页 > 正文

【设计模式】详解观察者模式

2024-04-01 00:47:05阅读 2

1、简介

观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,它的所有依赖者都会收到通知并自动更新。(MQ和它有点像)
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。
在这里插入图片描述
观察者模式中,一共有四种角色:

  1. Subject(抽象主题):也称为被观察者或可观察者,它是具有状态的对象,并维护着一个观察者列表。抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者。主题提供了添加、删除和通知观察者的方法。一般用一个抽象类或者一个接口实现
  2. Observer(抽象观察者):为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。抽象观察者角色一般用一个抽象类或者一个接口实现。在这个示意性的实现中,更新接口只包含一个方法(即Update()方法),这个方法叫做更新方法。
  3. ConcreteSubject(具体主题):也可称为具体被观察者,该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
  4. ConcrereObserver(具体观察者):实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。如果需要,具体现察者角色可以保存一个指向具体主题对象的引用。

从具体主题角色指向抽象观察者角色的合成关系,代表具体主题对象可以有任意多个对抽象观察者对象的引用。之所以使用抽象观察者而不是具体观察者,意味着主题对象不需要知道引用了哪些ConcreteObserver类型,而只知道抽象Observer类型。这就使得具体主题对象可以动态地维护一系列的对观察者对象的引用,并在需要通知的时候调用每一个观察者共有的update()更新方法。这种做法叫做"针对抽象编程"。

2、观察者模式简单实现

拿博客专栏订阅为例,网站用户的博客专栏为被观察者,用户为观察者,当有多个用户关注了yhz的JVM专栏,当yhz的JVM专栏更新时就会通知这些订阅的用户。

抽象主题(Subject)

package DesignModel.Observer;

import java.util.ArrayList;

/**
 * @BelongsProject: 3.9.demo
 * @Author: yhz
 * @CreateTime: 2023-07-26  17:58
 * @Description: TODO
 * @Version: 1.0
 */
public abstract class Subject {
    //定义一个订阅者集合用于存储所有订阅了这个专栏的用户对象
    protected ArrayList<Observer>observers = new ArrayList();
    //注册方法,用于向订阅者集合中增加一个订阅者
    public void attach( Observer observer ) {
        observers.add( observer );
    }
    //注销方法,用于在订阅者集合中删除一个订阅者
    public void detach( Observer observer ) {
        observers.remove( observer );
    }
    //通知所有订阅者更新消息
    public abstract void notifyObservers(String message);
}

具体主题(ConcreteSubject)

yhz的这个专栏为具体主题,里面存储了订阅该专栏的网站用户,并实现了抽象主题中的通知方法:

package DesignModel.Observer;

/**
 * @BelongsProject: 3.9.demo
 * @Author: yhz
 * @CreateTime: 2023-07-26  18:18
 * @Description: TODO
 * @Version: 1.0
 */
public class ConcreteSubject extends Subject{

    //重写通知方法为自己的
    @Override
    public void notifyObservers(String message) {
        //通知订阅了该主题的所有订阅者
        for(Observer observer:observers){
            observer.update(message);
        }
    }
}

抽象观察者(Observer)

package DesignModel.Observer;

public interface Observer {
    
    //声明了更i性能方法
    void update(String message);
}

具体观察者(ConcrereObserver)

网站用户作为具体观察者,里面实现了更新的方法

package DesignModel.Observer;

/**
 * @BelongsProject: 3.9.demo
 * @Author: yhz
 * @CreateTime: 2023-07-26  18:06
 * @Description: TODO
 * @Version: 1.0
 */
public class Blooger implements Observer{
	//博主名称
    private String bloogerName;

    public Blooger(String bloogerName) {
        this.bloogerName = bloogerName;
    }

    @Override
    public void update(String message) {
        System.out.println(bloogerName+message);
    }
}

测试:

package DesignModel.Observer;

/**
 * @BelongsProject: 3.9.demo
 * @Author: yhz
 * @CreateTime: 2023-07-26  18:21
 * @Description: TODO
 * @Version: 1.0
 */
public class Test {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        Blooger blooger = new Blooger("aa1");
        Blooger blooger2 = new Blooger("aa2");
        Blooger blooger3 = new Blooger("aa3");
        Blooger blooger4 = new Blooger("aa4");

        subject.attach(blooger);
        subject.attach(blooger2);
        subject.attach(blooger3);
        subject.attach(blooger4);

        subject.notifyObservers("您关注的yhz更新了博客");
    }
}

结果打印:

aa1您关注的yhz更新了博客
aa2您关注的yhz更新了博客
aa3您关注的yhz更新了博客
aa4您关注的yhz更新了博客

观察者设计模式优缺点

观察者模式的优点包括:

  • 降低了主题与观察者之间的耦合关系,两者之间是抽象耦合关系。可以很容易扩展观察者和被观察者。
  • 主题与观察者之间建立了一套触发机制。

观察者模式的缺点包括:

  • 主题与观察者之间的依赖关系并没有完全解除。
  • 当观察者对象很多时,通知的发布会花费很长时间,影响程序效率。
  • 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
  • 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。

在使用观察者模式时,需要谨慎处理这些问题,以确保系统的稳定性和效率。

网站文章

  • ap计算机科学 容错率,2020年 AP CSA(计算机科学)考试真题考点分析及答题思路讲解-2020年AP CSA考情回顾...

    ap计算机科学 容错率,2020年 AP CSA(计算机科学)考试真题考点分析及答题思路讲解-2020年AP CSA考情回顾...

    嗨同学们大家好呀,在北京时间5.16号凌晨四点开考CSA,亲爱的TD小伙伴们,你们考的怎么样?由于为了防止有考生作弊,CB这次也是拼尽全力,准备了多套试卷,如果大家遇到了本篇推送中没有cover到的题...

    2024-04-01 00:46:40
  • -XX:NewSize=20m -XX:MaxNewSize=40m,-Xmn30m,-XX:NewRatio=5

    -XX:NewSize=20m -XX:MaxNewSize=40m,-Xmn30m,-XX:NewRatio=5

    【代码】-XX:NewSize=20m -XX:MaxNewSize=40m,-Xmn30m,-XX:NewRatio=5。

    2024-04-01 00:46:33
  • 年薪30万才能算码农,你顶多就是码畜...

    年薪30万才能算码农,你顶多就是码畜...

    图灵、香农、冯诺依曼等人。:AT&T 贝尔实验室里那几个开创了计算机世界的研究员,Thompson、里奇、伯纳斯李、Bjarne Stroustrup 等人。:仙童公司八叛逆天才 ( 罗伯特 · 诺伊...

    2024-04-01 00:46:25
  • NoSQL Manager for MongoDB 教程(基础篇)

    NoSQL Manager for MongoDB 教程(基础篇)

    前段时间,学习了一下mongodb,在客户端工具方面,个人认为NoSQL Manager for MongoDB 是体验比较好的一个,功能也较齐全。可惜在找教程的时候,发现很难找到比较详细的教程,也没...

    2024-04-01 00:46:00
  • 金蝶s-HR远程调试拒绝

    金蝶s-HR远程调试拒绝

    该配置的都配置了,jar包也引入无报错了。元数据也发布了。端口也改成了其他未占用的端口

    2024-04-01 00:45:54
  • js每隔一秒打印一个数,打印1 2 3 4 5

    js每隔一秒打印一个数,打印1 2 3 4 5

    如题,一般按照我们的思路:1.写一个循环,循环5次,打印这个数2.每隔一秒打印一次,用到setTimeout于是,我们很容易写出最后我们发现,打印出了 5 5 5 5 5为什么呢,这个题其实考察的就是...

    2024-04-01 00:45:47
  • 优化Solr schemalXML 设置

    优化Solr schemalXML 设置

    Solr 框架中域配置文件schema.xml定义了文档(document)所包含的字段(field)。当对document建立索引或者查询时,这些字段将会被处理。因此,这个文件中的字段设置好不好,直...

    2024-04-01 00:45:21
  • redis配置文件

    # redis 配置文件示例 # 当你需要为某个配置项指定内存大小的时候,必须要带上单位,# 通常的格式就是 1k 5gb 4m 等酱紫:## 1k => 1000 bytes# 1kb => 1024 bytes# 1m => 1000000 bytes# 1mb => 1024*1024 bytes# 1g => 1000000000 b...

    2024-04-01 00:45:12
  • 关于空洞卷积(Atrous Convolution)

    关于空洞卷积(Atrous Convolution)

    内容节选自《神经网络与深度学习》电子版:https://nndl.github.io/ 对于一个卷积层,如果希望增加输出单元的感受野,一般可以通过三种方式 实现: 1)增加卷积核的大小; 2)增加层数...

    2024-04-01 00:45:04
  • echarts世界地图,国家名称翻译

    echarts世界地图,地名翻译

    2024-04-01 00:44:57