当前位置: 首页 > news >正文

观察者模式(Observer Pattern)

观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,当这个主题对象的状态发生变化时,会通知所有观察者对象,并自动更新它们的状态。以下是对观察者模式的详细解析:

一、定义与特点

  • 定义:观察者模式是一种对象行为模式,用于在对象之间建立一对多的依赖关系,以便当一个对象的状态发生变化时,所有依赖于它的对象都得到通知并被自动更新。
  • 特点
    • 松耦合:主题和观察者之间通过抽象接口进行交互,使得它们可以独立演化而不影响彼此。
    • 一对多关系:一个主题可以有多个观察者,并且它们之间没有直接联系。
    • 可扩展性:可以随时增加新的观察者或删除现有观察者。
    • 解耦合:将主题与具体观察者解耦,使得它们可以独立地变化和复用。
    • 实时性:实现了实时更新机制,当主题状态改变时能够即刻通知相关观察者。

二、角色与职责

  • Subject(主题)
    • 抽象主题角色:把所有观察者对象保存在一个集合里,提供注册和删除观察者对象的接口。
    • 具体主题角色:实现抽象主题角色所提供的接口,当内部状态发生改变时,给所有注册的观察者发出通知。
  • Observer(观察者)
    • 抽象观察者角色:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。
    • 具体观察者角色:实现抽象观察者角色所要求的更新接口,以便在得到主题的通知时更新自身的状态。

三、实现方式

观察者模式的实现方式多种多样,但从根本上说,必须包含观察者和被观察对象两个角色。通常,会定义一个观察者接口和一个主题接口,然后创建具体的观察者和主题类来实现这些接口。主题类中会维护一个观察者列表,并在状态改变时遍历通知所有观察者。

四、应用场景

观察者模式在实际应用中具有广泛的应用场景,包括但不限于以下几个方面:

  • 事件处理:在图形用户界面(GUI)框架中,按钮的点击事件、窗口的打开和关闭事件等都可以使用观察者模式进行处理。
  • 消息通知:在消息通知系统中,当发布者发布新消息时,订阅该消息的观察者将收到通知并进行相应的处理。
  • 发布-订阅模式:观察者模式常与发布-订阅模式结合使用,在发布者和订阅者之间通过消息代理进行通信。
  • GUI开发:在图形用户界面(GUI)开发中,当用户与界面上的元素进行交互时,观察者模式可以用于将这些交互事件通知给相应的观察者,从而触发相应的操作或更新界面。
  • 股票市场:股票交易所可以充当被观察者,而股票交易员可以充当观察者。当股票的价格、交易量等发生变化时,交易员将接收到通知并采取相应的行动。
  • 日志记录:在实时日志记录系统中,日志记录器充当被观察者,而观察者可以是日志分析器、报警系统等。

五、优缺点

  • 优点
    • 观察者和被观察者之间建立了抽象的耦合关系,提高了系统的灵活性和可扩展性。
    • 实现了动态联动,当一个对象的状态发生变化时,能够自动通知所有依赖它的对象。
  • 缺点
    • 如果一个被观察者有很多观察者,通知到所有观察者可能会很耗时,影响系统的性能。
    • 被观察者只知道观察者发生了变化,但不知道具体发生了什么变化,这可能导致观察者无法做出准确的响应。

总之,观察者模式是一种非常有用的设计模式,它能够在对象之间建立松耦合的依赖关系,实现对象之间的动态联动和实时更新。然而,在使用时也需要注意其潜在的缺点和限制。

五、例子

在Java中实现观察者模式,我们通常会定义一个主题(Subject)接口和一个观察者(Observer)接口。然后,创建具体的主题类和观察者类来实现这些接口。下面是一个简单的Java示例,展示了如何实现观察者模式。

首先,我们定义Observer观察者接口,它包含一个update方法,当主题状态变化时,该方法将被调用。

// Observer.java  
public interface Observer {  void update(String message);  
}

接着,我们定义Subject接口,它包含注册、删除观察者和通知所有观察者的方法。

// Subject.java  
import java.util.ArrayList;  
import java.util.List;  public interface Subject {  void registerObserver(Observer o);  void removeObserver(Observer o);  void notifyObservers(String message);  
}

现在,我们创建一个具体的主题类ConcreteSubject来实现Subject接口。

// ConcreteSubject.java  
import java.util.ArrayList;  
import java.util.List;  public class ConcreteSubject implements Subject {  private List<Observer> observers;  private String state;  public ConcreteSubject() {  observers = new ArrayList<>();  }  @Override  public void registerObserver(Observer o) {  observers.add(o);  }  @Override  public void removeObserver(Observer o) {  int i = observers.indexOf(o);  if (i >= 0) {  observers.remove(i);  }  }  @Override  public void notifyObservers(String message) {  for (Observer observer : observers) {  observer.update(message);  }  }  public void setState(String state) {  this.state = state;  notifyObservers("Subject state changed to: " + state);  }  public String getState() {  return state;  }  
}

最后,我们创建一个或多个具体的观察者类来实现Observer接口。

// ConcreteObserver.java  
public class ConcreteObserver implements Observer {  private String name;  private String observerState;  public ConcreteObserver(String name) {  this.name = name;  }  @Override  public void update(String message) {  observerState = message;  display();  }  public void display() {  System.out.println(name + " received: " + observerState);  }  
}

现在,我们可以编写一个客户端类来测试我们的观察者模式实现。

// ObserverPatternDemo.java  
public class ObserverPatternDemo {  public static void main(String[] args) {  ConcreteSubject subject = new ConcreteSubject();  Observer observer1 = new ConcreteObserver("Observer 1");  Observer observer2 = new ConcreteObserver("Observer 2");  Observer observer3 = new ConcreteObserver("Observer 3");  subject.registerObserver(observer1);  subject.registerObserver(observer2);  subject.registerObserver(observer3);  subject.setState("New State");  subject.removeObserver(observer1);  subject.setState("Another State");  }  
}

在这个例子中,ConcreteSubject是主题,它维护了一个观察者列表。当主题的状态改变时,它调用notifyObservers方法来通知所有注册的观察者。每个ConcreteObserver实例都是观察者,它们实现了update方法来接收来自主题的通知,并根据需要更新自己的状态。在客户端代码中,我们创建了三个观察者实例,并将它们注册到主题上。然后,我们更改主题的状态,并查看观察者的响应。最后,我们删除了一个观察者,并再次更改主题的状态以查看剩余观察者的响应。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • C# 设计模式之桥接模式
  • 新质生产力
  • PHP中如何定义常量以及常量和变量的主要区别
  • 海思35XX系列(三)sensor(传感器)
  • VUE框架面试整理-模板语法
  • EfficientNet-v2-s图像分类训练(简洁版)
  • DataX介绍
  • Python模块中的全局变量
  • Mecanim Animation System
  • Golang | Leetcode Golang题解之第310题最小高度树
  • 音视频入门基础:WAV专题(5)——FFmpeg源码中解码WAV Header的实现
  • Linux Socket TCP处理粘包问题
  • 实现基于 Python 和 xterm.js 的 Web 交互终端demo
  • 掌控情绪,驾驭人生,在人生的漫长旅程中,情绪如同多变的天气,时而风和日丽,时而狂风骤雨
  • pypinyin,一个有趣的 Python 库!
  • [iOS]Core Data浅析一 -- 启用Core Data
  • 【刷算法】求1+2+3+...+n
  • 【跃迁之路】【463天】刻意练习系列222(2018.05.14)
  • C++回声服务器_9-epoll边缘触发模式版本服务器
  • Django 博客开发教程 16 - 统计文章阅读量
  • JavaScript工作原理(五):深入了解WebSockets,HTTP/2和SSE,以及如何选择
  • jQuery(一)
  • Logstash 参考指南(目录)
  • Mithril.js 入门介绍
  • Octave 入门
  • Stream流与Lambda表达式(三) 静态工厂类Collectors
  • Vue UI框架库开发介绍
  • vue-router的history模式发布配置
  • 第13期 DApp 榜单 :来,吃我这波安利
  • 订阅Forge Viewer所有的事件
  • 区块链共识机制优缺点对比都是什么
  • 深度学习在携程攻略社区的应用
  • 原生 js 实现移动端 Touch 滑动反弹
  • 智能网联汽车信息安全
  • 转载:[译] 内容加速黑科技趣谈
  • 蚂蚁金服CTO程立:真正的技术革命才刚刚开始
  • ​埃文科技受邀出席2024 “数据要素×”生态大会​
  • ​低代码平台的核心价值与优势
  • #Z2294. 打印树的直径
  • #我与Java虚拟机的故事#连载11: JVM学习之路
  • (2022版)一套教程搞定k8s安装到实战 | RBAC
  • (delphi11最新学习资料) Object Pascal 学习笔记---第14章泛型第2节(泛型类的类构造函数)
  • (react踩过的坑)antd 如何同时获取一个select 的value和 label值
  • (WSI分类)WSI分类文献小综述 2024
  • (二刷)代码随想录第15天|层序遍历 226.翻转二叉树 101.对称二叉树2
  • (附源码)springboot 基于HTML5的个人网页的网站设计与实现 毕业设计 031623
  • (附源码)ssm高校运动会管理系统 毕业设计 020419
  • (数据大屏)(Hadoop)基于SSM框架的学院校友管理系统的设计与实现+文档
  • (四)【Jmeter】 JMeter的界面布局与组件概述
  • (四)JPA - JQPL 实现增删改查
  • (四)进入MySQL 【事务】
  • *** 2003
  • . Flume面试题
  • .equals()到底是什么意思?
  • .NET 将混合了多个不同平台(Windows Mac Linux)的文件 目录的路径格式化成同一个平台下的路径