设计模式-观察者模式(Observer)

设计模式-观察者模式(Observer)

    • 一、观察者模式概述
      • 1.1 什么是观察者模式
      • 1.2 简单实现观察者模式
      • 1.3 使用观察者模式的注意事项
    • 二、观察者模式的用途
    • 三、观察者模式实现方式
      • 3.1 使用接口实现观察者模式
      • 3.2 使用抽象类和具体子类实现观察者模式
      • 3.3 使用 Java 内置的 Observable 和 Observer 类实现观察者模式
      • 3.4 使用事件监听器实现观察者模式
      • 3.5 使用发布-订阅模式实现观察者模式

一、观察者模式概述

1.1 什么是观察者模式

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

观察者模式包含以下角色:

主题(Subject):被观察的对象,维护一个观察者列表,提供添加、删除和通知观察者的方法。
观察者(Observer):观察主题对象的状态变化,实现 Update 方法来更新自己的状态。
具体主题(ConcreteSubject):继承自抽象主题,实现具体业务逻辑。
具体观察者(ConcreteObserver):继承自抽象观察者,实现具体业务逻辑。
使用观察者模式可以使得系统更加灵活、可扩展,减少各个模块之间的耦合度。

1.2 简单实现观察者模式

Java观察者模式是一种行为设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

以下是一个简单的Java观察者模式实现:

首先,创建一个观察者接口Observer,包含一个update方法,用于在主题状态发生变化时更新观察者的状态:

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

然后,创建一个主题接口Subject,包含添加、删除和通知观察者的方法:

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

接下来,创建一个具体的主题类ConcreteSubject,实现Subject接口:

public class ConcreteSubject implements Subject {private List<Observer> observers = new ArrayList<>();private String state;@Overridepublic void addObserver(Observer observer) {observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers(String message) {for (Observer observer : observers) {observer.update(message);}}public void setState(String state) {this.state = state;notifyObservers("State changed to: " + state);}
}

最后,创建一个具体的观察者类ConcreteObserver,实现Observer接口:

public class ConcreteObserver implements Observer {private String name;private String state;public ConcreteObserver(String name) {this.name = name;}@Overridepublic void update(String message) {System.out.println(name + " received message: " + message);state = message;}
}

使用示例:

public class Main {public static void main(String[] args) {ConcreteSubject subject = new ConcreteSubject();Observer observer1 = new ConcreteObserver("Observer1");Observer observer2 = new ConcreteObserver("Observer2");Observer observer3 = new ConcreteObserver("Observer3");subject.addObserver(observer1);subject.addObserver(observer2);subject.addObserver(observer3);subject.setState("New State");}
}

运行上述代码,可以看到三个观察者对象分别接收到了主题状态变化的通知。

1.3 使用观察者模式的注意事项

  • 1、主题对象和观察者对象的耦合度要尽可能低,避免出现循环引用的情况。
  • 2、主题对象的通知方式要保持一致,避免出现通知失败或者丢失的情况。
  • 3、观察者对象的 Update 方法的实现要避免过于复杂,尽量保持简单易懂。
  • 4、在添加、删除观察者对象时要考虑到线程安全问题,可以使用同步机制来保证线程安全。
  • 5、当主题对象的状态变化较为频繁时,可能会导致大量的通知操作,从而影响系统的性能。在这种情况下可以考虑使用异步消息队列等技术来优化性能。

二、观察者模式的用途

  • 1、实现了对象之间的解耦。主题对象和观察者对象的耦合度尽可能低,避免了循环引用的情况。
  • 2、支持一种一对多的依赖关系。一个主题对象状态改变时,所有依赖于它的观察者对象都会被自动通知并更新。
  • 3、帮助编写更加松耦合的代码及实现事件的广播通知。尤其在主题对象的状态变化较为频繁时,通过使用观察者模式,可以避免大量的通知操作影响系统性能。
  • 4、适用于多种场景,包括但不限于GUI应用程序、事件处理系统等。如在Java自带的观察者模式中,JDK提供了Observer接口作为监听者,Observable类作为观察者的实现。
  • 5、对高度协作提供了支持。当一个对象(目标对象)的状态发生改变时,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。

三、观察者模式实现方式

3.1 使用接口实现观察者模式

观察者模式是一种行为设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象的状态发生变化时,所有依赖于它的观察者对象都会得到通知并自动更新。

下面是使用 Java 接口实现观察者模式的示例代码:

// 定义观察者接口
interface Observer {void update(String message);
}// 定义主题接口
interface Subject {void addObserver(Observer observer);void removeObserver(Observer observer);void notifyObservers();
}// 具体主题类
class ConcreteSubject implements Subject {private List<Observer> observers = new ArrayList<>();private String state;public void setState(String state) {this.state = state;notifyObservers();}@Overridepublic void addObserver(Observer observer) {observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update(state);}}
}// 具体观察者类
class ConcreteObserver implements Observer {private String name;public ConcreteObserver(String name) {this.name = name;}@Overridepublic void update(String message) {System.out.println("Observer " + name + " received message: " + message);}
}// 测试代码
public class Main {public static void main(String[] args) {ConcreteSubject subject = new ConcreteSubject();Observer observer1 = new ConcreteObserver("A");Observer observer2 = new ConcreteObserver("B");Observer observer3 = new ConcreteObserver("C");subject.addObserver(observer1);subject.addObserver(observer2);subject.addObserver(observer3);subject.setState("New State");}
}

在上面的示例中,我们首先定义了两个接口 Observer 和 Subject,分别表示观察者和主题。然后,我们创建了一个具体的主题类 ConcreteSubject,它实现了 Subject 接口,并维护了一个观察者列表。当主题的状态发生变化时,它会调用 notifyObservers 方法通知所有的观察者。我们还创建了一个具体的观察者类 ConcreteObserver,它实现了 Observer 接口,并在接收到通知时打印一条消息。最后,在测试代码中,我们创建了一个主题对象和三个观察者对象,并将它们添加到主题的观察者列表中。当我们设置主题的状态时,所有的观察者都会收到通知并打印出相应的消息。

3.2 使用抽象类和具体子类实现观察者模式

观察者模式是一种行为设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象的状态发生变化时,所有依赖于它的观察者对象都会得到通知并自动更新。

下面是使用抽象类和具体子类实现观察者模式的示例代码:

// 定义观察者接口
interface Observer {void update(String message);
}// 定义主题接口
interface Subject {void addObserver(Observer observer);void removeObserver(Observer observer);void notifyObservers();
}// 具体主题类
class ConcreteSubject implements Subject {private List<Observer> observers = new ArrayList<>();private String state;public void setState(String state) {this.state = state;notifyObservers();}@Overridepublic void addObserver(Observer observer) {observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update(state);}}
}// 具体观察者类A
class ConcreteObserverA implements Observer {private String name;public ConcreteObserverA(String name) {this.name = name;}@Overridepublic void update(String message) {System.out.println("Observer A received message: " + message);}
}// 具体观察者类B
class ConcreteObserverB implements Observer {private String name;public ConcreteObserverB(String name) {this.name = name;}@Overridepublic void update(String message) {System.out.println("Observer B received message: " + message);}
}// 测试代码
public class Main {public static void main(String[] args) {ConcreteSubject subject = new ConcreteSubject();Observer observerA = new ConcreteObserverA("A");Observer observerB = new ConcreteObserverB("B");subject.addObserver(observerA);subject.addObserver(observerB);subject.setState("New State");}
}

在上面的示例中,我们首先定义了观察者接口 Observer 和主题接口 Subject,然后创建了一个具体的主题类 ConcreteSubject,它实现了 Subject 接口,并维护了一个观察者列表。当主题的状态发生变化时,它会调用 notifyObservers 方法通知所有的观察者。我们还创建了两个具体的观察者类 ConcreteObserverA 和 ConcreteObserverB,它们都实现了 Observer 接口,并在接收到通知时打印出相应的消息。最后,在测试代码中,我们创建了一个主题对象和两个观察者对象,并将它们添加到主题的观察者列表中。当我们设置主题的状态时,所有的观察者都会收到通知并打印出相应的消息。

3.3 使用 Java 内置的 Observable 和 Observer 类实现观察者模式

要使用Java内置的Observable和Observer类实现观察者模式,首先需要创建一个继承要使用Java内置的Observable和Observer类实现观察者模式,首先需要创建一个继承自Observable的类,然后在该类中定义一个或多个状态变量。当这些状态变量发生变化时,调用setChanged()方法通知所有观察者。接下来,创建一个继承自Observer的类,重写update()方法以处理状态变化的通知。

以下是一个简单的示例:

创建一个继承自Observable的类,例如Subject:

import java.util.Observable;public class Subject extends Observable {private String state;public String getState() {return state;}public void setState(String state) {this.state = state;setChanged(); // 通知观察者状态已改变notifyObservers(state); // 传递新状态给观察者}
}

创建一个继承自Observer的类,例如MyObserver:

import java.util.Observer;public class MyObserver implements Observer {@Overridepublic void update(Observable o, Object arg) {if (o instanceof Subject) {System.out.println("状态已更新为:" + arg);}}
}

在主程序中使用这两个类:

public class Main {public static void main(String[] args) {Subject subject = new Subject();MyObserver observer = new MyObserver();subject.addObserver(observer); // 添加观察者subject.setState("状态1"); // 设置状态并通知观察者subject.setState("状态2"); // 设置状态并通知观察者}
}

运行上述代码,将看到以下输出:

状态已更新为:状态1
状态已更新为:状态2

3.4 使用事件监听器实现观察者模式

在Java中,可以使用事件监听器实现观察者模式。以下是一个简单的示例:

首先,创建一个事件类Event,用于传递事件信息:

public class Event {private Object source;public Event(Object source) {this.source = source;}public Object getSource() {return source;}
}

然后,创建一个事件监听器接口EventListener,用于处理事件:

public interface EventListener {void handleEvent(Event event);
}

接下来,创建一个具体的事件源类EventSource,用于注册和触发事件

import java.util.ArrayList;
import java.util.List;public class EventSource {private List<EventListener> listeners = new ArrayList<>();public void addEventListener(EventListener listener) {listeners.add(listener);}public void removeEventListener(EventListener listener) {listeners.remove(listener);}public void fireEvent(Event event) {for (EventListener listener : listeners) {listener.handleEvent(event);}}
}

最后,创建一个具体的观察者类ConcreteObserver,实现EventListener接口

public class ConcreteObserver implements EventListener {@Overridepublic void handleEvent(Event event) {System.out.println("收到事件:" + event.getSource());}
}

在主程序中使用这些类:

public class Main {public static void main(String[] args) {EventSource eventSource = new EventSource();ConcreteObserver observer = new ConcreteObserver();eventSource.addEventListener(observer);eventSource.fireEvent(new Event("事件1"));eventSource.fireEvent(new Event("事件2"));}
}

运行上述代码,将看到以下输出:

收到事件:事件1
收到事件:事件2

3.5 使用发布-订阅模式实现观察者模式

在Java中,可以使用java.util.Observable类和java.util.Observer接口实现发布-订阅模式。以下是一个简单的示例:

首先,创建一个继承自java.util.Observable的类,例如Publisher:

import java.util.Observable;public class Publisher extends Observable {private String message;public void setMessage(String message) {this.message = message;setChanged(); // 标记状态已改变notifyObservers(message); // 通知所有观察者}
}

然后,创建一个实现java.util.Observer接口的类,例如Subscriber:

import java.util.Observer;public class Subscriber implements Observer {private String name;public Subscriber(String name) {this.name = name;}@Overridepublic void update(Observable o, Object arg) {System.out.println(name + "收到消息: " + arg);}
}

最后,在主程序中使用这两个类:

public class Main {public static void main(String[] args) {Publisher publisher = new Publisher();Subscriber subscriber1 = new Subscriber("订阅者1");Subscriber subscriber2 = new Subscriber("订阅者2");publisher.addObserver(subscriber1);publisher.addObserver(subscriber2);publisher.setMessage("Hello, World!");}
}

运行这个程序,你将看到以下输出:

订阅者1收到消息: Hello, World!
订阅者2收到消息: Hello, World!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/141447.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Rust语言基础:从Hello World开始

大家好&#xff0c;我是[lincyang]。 我们将一起探索Rust语言的基础&#xff0c;从最经典的程序入手——“Hello, World!”。 Rust简介 Rust是一种系统编程语言&#xff0c;由Mozilla赞助开发&#xff0c;旨在提供内存安全、并发性和实用性。它的设计思想强调安全性和性能&…

CSS怎么选择除了第一个子元素外的其余同级子元素

使用 CSS 的:not()伪类选择器和:nth-child()伪类选择器 要通过CSS的代码选择某一个元素的除了第一个子元素外的其余的跟第一个子元素同级的子元素&#xff0c;可以结合使用CSS的:not()伪类选择器和:nth-child()伪类选择器进行选择。大致的语法如下&#xff1a; .parent > …

【EI会议征稿】第七届结构工程与工业建筑国际学术会议(ICSEIA 2024)

第七届结构工程与工业建筑国际学术会议&#xff08;ICSEIA 2024&#xff09; 2024 7th International Conference on Structural Engineering and Industrial Architecture 随着城市化进程的不断深入&#xff0c;建筑领域的需求也在优化、调整。结构工程的发展依旧受到重视&am…

c语言-数据结构-链表分割

链表分割实际上是给定一个值&#xff0c;遍历链表把链表中小于该值的节点与大于该值的节点分开&#xff0c;一般是将小于该值的节点放到链表的前面部分&#xff0c;大于该值的节点放在链表的后面部分。 链表分割示意图如下&#xff1a; 思路&#xff1a; 首先创建两条带哨兵位节…

CSDN每日一题学习训练——Java版(字符串相乘、子集、删除链表的倒数第 N 个结点)

版本说明 当前版本号[20231112]。 版本修改说明20231112初版 目录 文章目录 版本说明目录字符串相乘题目解题思路代码思路补充说明参考代码 子集题目解题思路代码思路参考代码 删除链表的倒数第 N 个结点题目解题思路代码思路参考代码 字符串相乘 题目 给定两个以字符串形…

【Linux】第十六站:进程地址空间

文章目录 一、程序地址空间1.内存的分布2.static修饰后为什么不会被释放3.一个奇怪的现象 二、进程地址空间1.前面现象的原因2.地址空间究竟是什么&#xff1f;3.为什么要有进程地址空间4.页表5.什么叫进程&#xff1f;6.进程具有独立性。为什么&#xff1f;怎么做到呢&#xf…

问题复盘|MySQL 数据记录中明明有值,使用 concat() 后得到的却一直是 null

背景 MySQL 的数据数据记录中明明有值&#xff0c;在使用 concat() 查询时却一直得到 null SELECT CONCAT(first_name, , last_name) FROM users;排查后发现 MySQL 的 concat 函数拼接规则是 当多个拼接的字段的字段值中存在 null 时&#xff0c;返回的一定是 null 解决方…

【算法】算法题-20231114

这里写目录标题 一、LCR 181. 字符串中的单词反转二、557. 反转字符串中的单词 III三、344. 反转字符串四、给定一个已按照升序排列的有序数组&#xff0c;找到两个数使得它们相加之和等于目标数。五、力扣第49题&#xff1a;字母异位词分组 一、LCR 181. 字符串中的单词反转 …

解决 Django 开发中的环境配置问题:Windows 系统下的实战指南20231113

简介&#xff1a; 在本文中&#xff0c;我想分享一下我最近在 Windows 环境下进行 Django 开发时遇到的一系列环境配置问题&#xff0c;以及我是如何一步步解决这些问题的。我的目标是为那些可能遇到类似困难的 Django 开发者提供一些指导和帮助。 问题描述&#xff1a; 最近…

2023.11.14-hive之表操作练习和文件导入练习

目录 需求1.数据库基本操作 需求2. 默认分隔符案例 需求1.数据库基本操作 -- 1.创建数据库test_sql,cs1,cs2,cs3 create database test_sql; create database cs1; create database cs2; create database cs3; -- 2.1删除数据库cs2 drop database cs2; -- 2.2在cs3库中创建…

optee4.0.0 qemu_v8环境搭建(支持Hafnium)

安全之安全(security)博客目录导读 目录 一、前提条件 二、拉取代码 三、下载工具链 四、编译 五、运行

了解防抖和节流:提升前端交互体验的实用策略

了解防抖和节流&#xff1a;提升前端交互体验的实用策略 前言什么是防抖&#xff1f;什么是节流&#xff1f;应用实例防抖实例节流实例 前言 本文将重点介绍前端性能优化方法之一的防抖和节流。首先解释了它们的概念和原理&#xff0c;然后探讨了它们在前端开发中的应用场景&a…

Spark数据倾斜优化

1 数据倾斜现象 1、现象 绝大多数task任务运行速度很快&#xff0c;但是就是有那么几个task任务运行极其缓慢&#xff0c;慢慢的可能就接着报内存溢出的问题。 2、原因 数据倾斜一般是发生在shuffle类的算子&#xff0c;比如distinct、groupByKey、reduceByKey、aggregateByKey…

链表相关部分OJ题

&#x1f493;作者简介&#x1f44f;&#xff1a;在校大二迷茫大学生 &#x1f496;个人主页&#x1f389;&#xff1a;小李很执着 &#x1f497;系列专栏&#xff1a;Leetcode经典题 每日分享&#xff1a;人总是在离开一个地方后开始原谅它❣️❣️❣️———————————…

pgsql_全文检索_使用空间换时间的方法支持中文搜索

pgsql_全文检索_使用空间换时间的方法支持中文搜索 一、环境 PostgreSQL 14.2, compiled by Visual C build 1914, 64-bit 二、引言 提到全文检索首先想到的就是ES(ElasticSearch)和Lucene&#xff0c;专业且强大。对于一些小众场景对于搜索要求不高&#xff0c;数据量也不…

10 Go的映射

概述 在上一节的内容中&#xff0c;我们介绍了Go的结构体&#xff0c;包括&#xff1a;定义结构体、声明结构体变量、使用结构体、结构体关联函数、new、组合等。在本节中&#xff0c;我们将介绍Go的映射。Go语言中的映射&#xff08;Map&#xff09;是一种无序的键值对集合&am…

【Hadoop】MapReduce详解

&#x1f984; 个人主页——&#x1f390;开着拖拉机回家_大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341; &#x1fa81;&#x1f341;&#x1fa81;&#x1f…

nodejs+vue+python+PHP+微信小程序-安卓-房产中介管理信息系统的设计与实现-计算机毕业设计

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

华为笔记本电脑原装win10/win11系统恢复安装教程方法

华为电脑matebook 14原装Win11系统带F10智能还原 安装恢复教程&#xff1a; 1.安装方法有两种&#xff0c;一种是用PE安装&#xff0c;一种是华为工厂包安装&#xff08;安装完成自带F10智能还原&#xff09; 若没有原装系统文件&#xff0c;请在这里获取&#xff1a;https:…

EasyDarwin开源流媒体服务器

文章目录 前言一、EasyDarwin 简介二、EasyDarwin 主要功能特点三、安装部署四、推拉流测试1、进入控制页面2、推流测试3、拉流测试 前言 本文介绍一个十分实用的高性能开源 RTSP 流媒体服务器&#xff1a;EasyDarwin。 一、EasyDarwin 简介 EasyDarwin 是基于 go 语言研发&a…