设计模式系列3 观察者模式

2023-11-01

什么是观察者模式?/观察者模式的定义?

在对象之间定义了一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象会收到通知并自动更新。说白了就是发布订阅模式,发布者发布信息,订阅者获取信息,订阅了就能收到信息,没订阅就收不到信息。

为什么用观察者模式?/用观察者模式有什么好处?

一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

优点:

  • 1、观察者和被观察者是抽象耦合的。
  • 2、建立一套触发机制。

缺点:

  • 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
  • 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
  • 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
使用场景
  • 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
  • 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
  • 一个对象必须通知其他对象,而并不知道这些对象是谁。
  • 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。

注意事项:

1、JAVA 中已经有了对观察者模式的支持类。

2、避免循环引用。

3、如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。

具体例子如:

  • 气象站服务,天气发生改变,关注者可以收到推送消息,取消关注就收不到推送消息。(Head First设计模式经典例子)
  • 微信公众号服务,不定时发布一些消息,关注公众号就可以收到推送消息,取消关注就收不到推送消息。
  • 博客服务,博客新增文章,关注者消息推送消息,取消关注就收不到推送消息。
例子(博客服务)

博客新增文章,关注者消息推送消息,取消关注就收不到推送消息。

编写博客主题接口BlogSubject

public interface BlogSubject {

    /**
     * 关注博客
     * @param follower
     */
    void addFollower(Follower follower);

    /**
     * 取消关注
     * @param follower
     */
    void removeFollower(Follower follower);

    /**
     * 主题状态发生改变时,通知所有的关注者
     */
    void notifyFollower();
}

编写BlogSubject的实现类

public class BlogSubjectData implements BlogSubject {

    /** 记录所有观察者 **/
    private ArrayList followers;
    private String article;

    public BlogSubjectData() {
        followers = new ArrayList();
    }

    @Override
    public void addFollower(Follower follower) {
        followers.add(follower);
    }

    @Override
    public void removeFollower(Follower follower) {
        followers.remove(follower);
    }

    @Override
    public void notifyFollower() {
        for (int i = 0; i < followers.size(); i++) {
            Follower follower = (Follower)followers.get(i);
            follower.update(article);
        }
    }

    public void setArticle(String article) {
        this.article = article;
        // 更新博客,需要通知关注者
        notifyFollower();
    }
}

定义关注者接口Follower

public interface Follower {
    void update(String article);
}

所有关注者都要实现关注者接口

编写FollowerFirst并实现Follower接口

public class FollowerFirst implements Follower {

    private BlogSubject blogSubject;

    /**
     * 构造器需要BlogSubject对象为了能够添加关注者
     * @param blogSubject
     */
    public FollowerFirst(BlogSubject blogSubject) {
        this.blogSubject = blogSubject;
        blogSubject.addFollower(this);
    }

    @Override
    public void update(String article) {
        System.out.println("关注者NO1,你关注的博主有新文章啦,文章名:"+article);
    }
}

编写FollowerSecond并实现Follower接口

public class FollowerSecond implements Follower {

    private BlogSubject blogSubject;
    /**
     * 构造器需要BlogSubject对象为了能够添加关注者
     * @param blogSubject
     */
    public FollowerSecond(BlogSubject blogSubject) {
        this.blogSubject = blogSubject;
        blogSubject.addFollower(this);
    }

    @Override
    public void update(String article) {
        System.out.println("关注者NO2,你关注的博主有新文章啦,文章名:"+article);
    }
}

编写测试类

public class BlogTest {
    public static void main(String[] args) {

        BlogSubjectData blogSubjectData = new BlogSubjectData();

        String article = "设计模式系列2 策略模式";
        FollowerFirst followerFirst = new FollowerFirst(blogSubjectData);
        FollowerSecond followerSecond = new FollowerSecond(blogSubjectData);
        blogSubjectData.setArticle(article);
        System.out.println("关注者NO2取消关注");
        blogSubjectData.removeFollower(followerSecond);
        article = "设计模式系列3 观察者模式";
        blogSubjectData.setArticle(article);
    }
}

运行输出结果

关注者NO1,你关注的博主有新文章啦,文章名:设计模式系列2 策略模式
关注者NO2,你关注的博主有新文章啦,文章名:设计模式系列2 策略模式
关注者NO2取消关注
关注者NO1,你关注的博主有新文章啦,文章名:设计模式系列3 观察者模式
总结

观察者模式是关于多个对象想知道一个对象中数据变化情况的一种成熟的模式。观察者模式中有一个称作“主题”的对象和若干个称作“观察者”的对象,“主题”和“观察者”间是一种一对多的依赖关系,当“主题”的状态发生变化时,所有“观察者”都得到通知。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

设计模式系列3 观察者模式 的相关文章

  • 如何为最终用户方便地启动Java GUI程序

    用户想要从以下位置启动 Java GUI 应用程序Windows 以及一些额外的 JVM 参数 例如 javaw Djava util logging config file logging properties jar MyGUI jar
  • Java new Date() 打印

    刚刚学习 Java 我知道这可能听起来很愚蠢 但我不得不问 System out print new Date 我知道参数中的任何内容都会转换为字符串 最终值是 new Date 返回对 Date 对象的引用 那么它是如何打印这个的呢 Mo
  • Spring Batch 多线程 - 如何使每个线程读取唯一的记录?

    这个问题在很多论坛上都被问过很多次了 但我没有看到适合我的答案 我正在尝试在我的 Spring Batch 实现中实现多线程步骤 有一个包含 100k 条记录的临时表 想要在 10 个线程中处理它 每个线程的提交间隔为 300 因此在任何时
  • Java - 将节点添加到列表的末尾?

    这是我所拥有的 public class Node Object data Node next Node Object data Node next this data data this next next public Object g
  • 在 HTTPResponse Android 中跟踪重定向

    我需要遵循 HTTPost 给我的重定向 当我发出 HTTP post 并尝试读取响应时 我得到重定向页面 html 我怎样才能解决这个问题 代码 public void parseDoc final HttpParams params n
  • JAXb、Hibernate 和 beans

    目前我正在开发一个使用 Spring Web 服务 hibernate 和 JAXb 的项目 1 我已经使用IDE hibernate代码生成 生成了hibernate bean 2 另外 我已经使用maven编译器生成了jaxb bean
  • 无法展开 RemoteViews - 错误通知

    最近 我收到越来越多的用户收到 RemoteServiceException 错误的报告 我每次给出的堆栈跟踪如下 android app RemoteServiceException Bad notification posted fro
  • Spark 1.3.1 上的 Apache Phoenix(4.3.1 和 4.4.0-HBase-0.98)ClassNotFoundException

    我正在尝试通过 Spark 连接到 Phoenix 并且在通过 JDBC 驱动程序打开连接时不断收到以下异常 为简洁起见 下面是完整的堆栈跟踪 Caused by java lang ClassNotFoundException org a
  • 控制Android的前置LED灯

    我试图在用户按下某个按钮时在前面的 LED 上实现 1 秒红色闪烁 但我很难找到有关如何访问和使用前置 LED 的文档 教程甚至代码示例 我的意思是位于 自拍 相机和触摸屏附近的 LED 我已经看到了使用手电筒和相机类 已弃用 的示例 但我
  • Liferay ClassNotFoundException:DLFileEntryImpl

    在我的 6 1 0 Portal 实例上 带有使用 ServiceBuilder 和 DL Api 的 6 1 0 SDK Portlet 这一行 DynamicQuery query DynamicQueryFactoryUtil for
  • 禁止的软件包名称:java

    我尝试从数据库名称为 jaane 用户名 Hello 和密码 hello 获取数据 错误 java lang SecurityException Prohibited package name java at java lang Class
  • 如何将 pfx 文件转换为 jks,然后通过使用 wsdl 生成的类来使用它来签署传出的肥皂请求

    我正在寻找一个代码示例 该示例演示如何使用 PFX 证书通过 SSL 访问安全 Web 服务 我有证书及其密码 我首先使用下面提到的命令创建一个 KeyStore 实例 keytool importkeystore destkeystore
  • 如何在控制器、服务和存储库模式中使用 DTO

    我正在遵循控制器 服务和存储库模式 我只是想知道 DTO 在哪里出现 控制器应该只接收 DTO 吗 我的理解是您不希望外界了解底层域模型 从领域模型到 DTO 的转换应该发生在控制器层还是服务层 在今天使用 Spring MVC 和交互式
  • Java列表的线程安全

    我有一个列表 它将在线程安全上下文或非线程安全上下文中使用 究竟会是哪一个 无法提前确定 在这种特殊情况下 每当列表进入非线程安全上下文时 我都会使用它来包装它 Collections synchronizedList 但如果不进入非线程安
  • 玩!框架:运行“h2-browser”可以运行,但网页不可用

    当我运行命令时activator h2 browser它会使用以下 url 打开浏览器 192 168 1 17 8082 但我得到 使用 Chrome 此网页无法使用 奇怪的是它以前确实有效 从那时起我唯一改变的是JAVA OPTS以启用
  • simpleframework,将空元素反序列化为空字符串而不是 null

    我使用简单框架 http simple sourceforge net http simple sourceforge net 在一个项目中满足我的序列化 反序列化需求 但在处理空 空字符串值时它不能按预期工作 好吧 至少不是我所期望的 如
  • 静态变量的线程安全

    class ABC implements Runnable private static int a private static int b public void run 我有一个如上所述的 Java 类 我有这个类的多个线程 在里面r
  • 在 Maven 依赖项中指定 jar 和 test-jar 类型

    我有一个名为 commons 的项目 其中包含运行时和测试的常见内容 在主项目中 我添加了公共资源的依赖项
  • 使用 JMF 创建 RTP 流时出现问题

    我正处于一个项目的早期阶段 需要使用 RTP 广播DataStream创建自MediaLocation 我正在遵循一些示例代码 该代码目前在rptManager initalize localAddress 出现错误 无法打开本地数据端口
  • 如何实现仅当可用内存较低时才将数据交换到磁盘的写缓存

    我想将应用程序生成的数据缓存在内存中 但如果内存变得稀缺 我想将数据交换到磁盘 理想情况下 我希望虚拟机通知它需要内存并将我的数据写入磁盘并以这种方式释放一些内存 但我没有看到任何方法以通知我的方式将自己挂接到虚拟机中before an O

随机推荐

  • Vue3项目搭建教程(create-vue)

    什么是create vue create vue是一个脚手架工具 用来快速创建v3的项目 Vuecli用来创建v2的项目 介绍 Vue CLI create vue是Vue官方新的脚手架工具 底层切换到了 vite 下一代前端工具链 为开发
  • 2021全国省市区街道(乡镇)数据及编码(不包含港澳台)

    已按拼音首字母排序 共31省直辖市 342个城市 3352个区县 41206个街道 乡镇 安徽省 340000 安庆市 340800 安徽安庆经济开发区 340871 菱北街道 340871001 老峰镇 340871100 大观区 340
  • 嵌入式Linux应用开发完全手册(一)嵌入式Linux基础知识

    嵌入式Linux应用开发完全手册 3 嵌入式Linux基础知识 3 1 交叉编译工具 编译工具链 编译工作由几个步骤完成 分别用到了不同的工具 PC端应用 gcc ld objcopy objdump 交叉编译 编译和运行在不同的环境下 a
  • mysql 5.6 创建索引导致表锁阻塞查询

    今天遇到一个表锁 对表进行select操作阻塞 最后发现在表操作时的时候执行了创建索引 导致整个表锁了 测试如下 1 先执行一个慢查询 mysql gt select sleep 500 from order log 2 对表进行创建索引操
  • 链式栈和队列以及重载,const,void(*)补充

    一 C 版链式栈和队列 1 1栈 include
  • 聊一聊TypeScript中的泛型与断言~

    思考 后端接口给前端返回数据时 一般会遵循一定的规律 例如 都有code msg data三个属性 而不同的接口返回的具体数据保存在data中 它的格式是不同的 随便定义一个数据 请求得到用户信息 const res1 code 200 m
  • Openwrt编写GPIO驱动控制LED

    一 驱动的编写 1 创建gpio control driver文件夹 2 在gpio control driver文件夹下再创建src文件夹以及Makefile文件 Makefile文件如下 include TOPDIR rules mk
  • ma5822是什么设备_ma5822是什么设备_华为MA5821-24 - AC远端光接入ONU光纤设备24口 全新原装...

    接口配置 8 FE提供SFP类型上行光接口 支持10G EPON EPON上行方式 16 FE MA582216 FE 16 POTS 面板丝印 交流电源接口 用于连接 接地点 用于设备接地 1个10G GPON GPON或者 维护串口CO
  • 时间序列分析状态空间模型粒子滤波器

    时间序列分析是研究时间序列数据的统计方法 而状态空间模型是一种描述时间序列的框架 粒子滤波器是一种用于状态空间模型的推断方法 下面我将详细解释时间序列分析 状态空间模型和粒子滤波器的概念以及它们之间的关系 时间序列分析是一种研究时间上观测数
  • 瞧瞧别人家的API接口,那叫一个优雅

    前言 在实际工作中 我们需要经常跟第三方平台打交道 可能会对接第三方平台API接口 或者提供API接口给第三方平台调用 那么问题来了 如果设计一个优雅的API接口 能够满足 安全性 可重复调用 稳定性 好定位问题等多方面需求 今天跟大家一起
  • 线程池的使用与分析(ThreadPoolExcutors)

    开发中为什么使用线程池 1 降低资源的消耗 通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗 2 提高响应速度 因为线程池中的线程数没有超过线程池的最大上限时 有的线程处于等待分配任务的状态 当任务来时无需创建新的线程就能执行 3
  • PyQT5 设置文本颜色

    from PyQt5 import QtWidgets import sys app QtWidgets QApplication sys argv dialog QtWidgets QDialog label1 QtWidgets QLa
  • linux net.ipv4.tcp_tw_reuse和net.ipv4.tcp_tw_recycle设置多大比较合适

    调整 net ipv4 tcp tw reuse 和 net ipv4 tcp tw recycle 这两个内核参数的值需要根据实际情况进行评估和测试 以下是对这两个参数的简要说明 net ipv4 tcp tw reuse 该参数控制是否
  • C语言数据结构 顺序表的输入与输出

    include
  • css 文字之间的间隔

    line height 行间距 ling height 属于用于设置行间距 就是行与行之间的距离 text aligh 水平对齐方式 text aligh属性用于设置文本内容的水平对齐 相当于html中的align对齐属性 其可用属性值 l
  • Apache Beam+Spark教程

    本文是基于Apache Beam 2 0编写代码 调用Apache Spark 1 6 2集群 读取Mongodb数据进行相应逻辑处理的例子 配置环境 首先通过Maven构建Apache Beam项目的依赖 不清楚的 可以去官网下载word
  • Castle Windsor 的AOP 实践

    前言 最近接手了一个二手项目 该项目的最大特点就是 拥有众多的上下游 外部产品或项目 运维时总会时不时出现各种异常 有系统本身的 有业务的 这时要求能最快定位到问题点 这就需要有详细的日志流来支撑这样的工作 翻开代码查看 记录日志的模式主要
  • 初学者了解mounted和this.$nextTick()的区别,在哪种情况下使用;

    其实看下图 就应该很清除的了解两个命令在vue中的执行阶段 就可以知道该如何使用了 两者的使用区别 mounted适合在初始化渲染完成后数据和页面没有发生变化的情况下使用 nextTick 适合初始化完成后 我们对数据进行操作并且页面发生了
  • win10+cuda10.0+vs2017+pytorch1.2.0+anaconda3+maskrcnn_benchmark+python3.6

    首先 版本不重要 cuda9 2也好9 0也好10 1也好 pytorch1 1 0也好 应该都能配置maskrcnn benchmark 为什么呢 网址 https github com NVIDIA apex issues 433 ht
  • 设计模式系列3 观察者模式

    什么是观察者模式 观察者模式的定义 在对象之间定义了一对多的依赖 这样一来 当一个对象改变状态 依赖它的对象会收到通知并自动更新 说白了就是发布订阅模式 发布者发布信息 订阅者获取信息 订阅了就能收到信息 没订阅就收不到信息 为什么用观察者