【设计模式】【行为型模式(Behavioral Patterns)】之观察者模式(Observer Pattern)

news2024/11/28 14:41:56

1. 设计模式原理说明

观察者模式(Observer Pattern) 是一种行为设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。这种模式非常适合处理事件驱动系统,其中对象之间需要保持同步但又不想紧密耦合。

主要角色
  1. Subject(主题/被观察者):它知道它的观察者是谁。任何数量的观察者都可以观察一个主题。提供注册和删除观察者对象的方法。
  2. Observer(观察者):为那些在主题发生改变时需获得通知的对象定义一个更新接口。
  3. ConcreteSubject(具体主题):将有关状态存储于具体观察者对象;当它的状态发生改变时,向它的各个观察者发出通知。
  4. ConcreteObserver(具体观察者):实现Observer的更新接口以使自身状态与主题的状态保持一致。

2. UML 类图及解释

UML 类图
+------------------+                +-----------------------+
|   Subject        |                |     Observer          |
|------------------|                |-----------------------|
| - observers: List<Observer> |     | - update(message: String): void |
| - register(observer: Observer) |   +-----------------------+
| - unregister(observer: Observer) |   |
| - notifyObservers(message: String) |   |
+------------------+                +-----------------------+
                                                   |
                                                   |
                                                   v
                                    +---------------------------+
                                    | ConcreteObserverA         |
                                    |--------------------------|
                                    | - update(message: String)  |
                                    +---------------------------+
                                                   ^
                                                   |
                                    +---------------------------+
                                    | ConcreteObserverB         |
                                    |--------------------------|
                                    | - update(message: String)  |
                                    +---------------------------+
类图解释
  • Subject:定义了添加、删除和通知观察者的接口。具体主题会实现这些方法,并维护一个观察者列表。
  • Observer:定义了一个更新接口,当主题发生变化时,观察者会被调用。
  • ConcreteSubject:实现了Subject接口,当其状态变化时,会通知所有已注册的观察者。
  • ConcreteObserverA 和 ConcreteObserverB:实现了Observer接口,当收到主题的通知时,会更新自己的状态。

3. 代码案例及逻辑详解

Java 代码案例
// 观察者接口
interface Observer {
    void update(String message);
}

// 具体观察者A
class ConcreteObserverA implements Observer {
    @Override
    public void update(String message) {
        System.out.println("ConcreteObserverA received: " + message);
    }
}

// 具体观察者B
class ConcreteObserverB implements Observer {
    @Override
    public void update(String message) {
        System.out.println("ConcreteObserverB received: " + message);
    }
}

// 被观察者接口
interface Subject {
    void register(Observer observer);
    void unregister(Observer observer);
    void notifyObservers(String message);
}

// 具体被观察者
class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();

    @Override
    public void register(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void unregister(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }

    public void changeState() {
        // 模拟状态变化
        System.out.println("State changed, notifying observers...");
        notifyObservers("State has been changed!");
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();

        Observer observerA = new ConcreteObserverA();
        Observer observerB = new ConcreteObserverB();

        subject.register(observerA);
        subject.register(observerB);

        subject.changeState();

        subject.unregister(observerA);
        subject.changeState();
    }
}
C++ 代码案例
#include <iostream>
#include <vector>
#include <algorithm>

// 观察者接口
class Observer {
public:
    virtual void update(const std::string& message) = 0;
    virtual ~Observer() {}
};

// 具体观察者A
class ConcreteObserverA : public Observer {
public:
    void update(const std::string& message) override {
        std::cout << "ConcreteObserverA received: " << message << std::endl;
    }
};

// 具体观察者B
class ConcreteObserverB : public Observer {
public:
    void update(const std::string& message) override {
        std::cout << "ConcreteObserverB received: " << message << std::endl;
    }
};

// 被观察者接口
class Subject {
private:
    std::vector<Observer*> observers;
public:
    void registerObserver(Observer* observer) {
        observers.push_back(observer);
    }

    void unregisterObserver(Observer* observer) {
        observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
    }

    void notifyObservers(const std::string& message) {
        for (Observer* observer : observers) {
            observer->update(message);
        }
    }

    void changeState() {
        // 模拟状态变化
        std::cout << "State changed, notifying observers..." << std::endl;
        notifyObservers("State has been changed!");
    }
};

// 客户端
int main() {
    Subject subject;

    Observer* observerA = new ConcreteObserverA();
    Observer* observerB = new ConcreteObserverB();

    subject.registerObserver(observerA);
    subject.registerObserver(observerB);

    subject.changeState();

    subject.unregisterObserver(observerA);
    subject.changeState();

    delete observerA;
    delete observerB;

    return 0;
}
Python 代码案例
# 观察者接口
class Observer:
    def update(self, message):
        raise NotImplementedError

# 具体观察者A
class ConcreteObserverA(Observer):
    def update(self, message):
        print(f"ConcreteObserverA received: {message}")

# 具体观察者B
class ConcreteObserverB(Observer):
    def update(self, message):
        print(f"ConcreteObserverB received: {message}")

# 被观察者接口
class Subject:
    def __init__(self):
        self._observers = []

    def register(self, observer):
        self._observers.append(observer)

    def unregister(self, observer):
        self._observers.remove(observer)

    def notify_observers(self, message):
        for observer in self._observers:
            observer.update(message)

    def change_state(self):
        # 模拟状态变化
        print("State changed, notifying observers...")
        self.notify_observers("State has been changed!")

# 客户端
if __name__ == "__main__":
    subject = Subject()

    observerA = ConcreteObserverA()
    observerB = ConcreteObserverB()

    subject.register(observerA)
    subject.register(observerB)

    subject.change_state()

    subject.unregister(observerA)
    subject.change_state()
Go 代码案例
package main

import (
	"fmt"
)

// 观察者接口
type Observer interface {
	update(message string)
}

// 具体观察者A
type ConcreteObserverA struct{}

func (c *ConcreteObserverA) update(message string) {
	fmt.Printf("ConcreteObserverA received: %s\n", message)
}

// 具体观察者B
type ConcreteObserverB struct{}

func (c *ConcreteObserverB) update(message string) {
	fmt.Printf("ConcreteObserverB received: %s\n", message)
}

// 被观察者接口
type Subject struct {
	observers []Observer
}

func (s *Subject) register(observer Observer) {
	s.observers = append(s.observers, observer)
}

func (s *Subject) unregister(observer Observer) {
	for i, obs := range s.observers {
		if obs == observer {
			s.observers = append(s.observers[:i], s.observers[i+1:]...)
			break
		}
	}
}

func (s *Subject) notifyObservers(message string) {
	for _, observer := range s.observers {
		observer.update(message)
	}
}

func (s *Subject) changeState() {
	// 模拟状态变化
	fmt.Println("State changed, notifying observers...")
	s.notifyObservers("State has been changed!")
}

// 客户端
func main() {
	subject := &Subject{}

	observerA := &ConcreteObserverA{}
	observerB := &ConcreteObserverB{}

	subject.register(observerA)
	subject.register(observerB)

	subject.changeState()

	subject.unregister(observerA)
	subject.changeState()
}

4. 总结

观察者模式 是一种行为设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。这种模式特别适用于事件驱动系统,其中对象之间需要保持同步但又不想紧密耦合。

主要优点
  1. 松耦合:观察者和被观察者之间的依赖关系非常松散,观察者不需要知道被观察者的具体实现细节。
  2. 支持广播通信:被观察者可以向所有注册的观察者广播消息,无需关心观察者的具体类型。
  3. 灵活性高:可以动态地添加或删除观察者,而不会影响其他观察者。
主要缺点
  1. 过度通知:如果被观察者的状态频繁变化,可能会导致大量不必要的通知。
  2. 复杂性增加:引入观察者模式会增加系统的复杂性,特别是当观察者和被观察者之间存在复杂的依赖关系时。
  3. 调试困难:由于观察者模式涉及多个对象之间的交互,调试时可能比较困难。
适用场景
  • 当一个对象的改变需要同时改变其他对象,而且不知道具体有多少对象需要改变时。
  • 当一个对象需要在另一个对象的状态发生变化时自动更新,但又不想紧密耦合时。
  • 当一个抽象模型有两个方面,其中一个方面依赖于另一方面,将这两者封装在独立的对象中以提高可复用性和灵活性时。

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

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

相关文章

使用IDEA构建springboot项目+整合Mybatis

目录 目录 1.Springboot简介 2.SpringBoot的工作流程 3.SpringBoot框架的搭建和配置 4.用Springboot实现一个基本的select操作 5.SpringBoot项目部署非常简单&#xff0c;springBoot内嵌了 Tomcat、Jetty、Undertow 三种容器&#xff0c;其默认嵌入的容器是 Tomcat&#xff0c;…

不玩PS抠图了,改玩Python抠图

网上找了两个苏轼的印章图片&#xff1a; 把这两个印章抠出来的话&#xff0c;对于不少PS高手来说是相当容易&#xff0c;但是要去掉其中的水印&#xff0c;可能要用仿制图章慢慢描绘&#xff0c;图章的边缘也要慢慢勾画或者用通道抠图之类来处理&#xff0c;而且印章的红色也不…

ElasticSearch的下载和基本使用(通过apifox)

1.概述 一个开源的高扩展的分布式全文检索引擎&#xff0c;近乎实时的存储&#xff0c;检索数据 2.安装路径 Elasticsearch 7.8.0 | Elastic 安装后启动elasticsearch-7.8.0\bin里的elasticsearch.bat文件&#xff0c; 启动后就可以访问本地的es库http://localhost:9200/ …

26届JAVA 学习日记——Day16

2024.11.27 周三 尽量在抽出时间做项目&#xff0c;持续学习优化简历&#xff0c;等到基础的八股都熟悉、leetcode热题100刷完、苍穹外卖项目AI项目彻底完成投简历&#xff0c;目标是找到日常实习&#xff0c;然后边做边准备暑期实习。 八股 WebSocket WebSocket是什么&…

Javaweb 前端 HTML css 案例 总结

顶部导航栏 弹性布局 搜索表单区域 表单标签 表单标签&#xff0c;表单项 复选&#xff0c;一次选多个 隐藏域&#xff0c;看不到&#xff0c;但会传参数 text输入框 radio单选 男女&#xff0c;是 前端页面上显示的值 搜索表单区域 button 按钮 表格数据展示区域 fo…

每日一练:【动态规划算法】斐波那契数列模型之使用最小花费爬楼梯(easy)

1. 题目链接&#xff1a;746. 使用最小花费爬楼梯 2. 题目描述 根据一般的思维&#xff0c;我们会认为本题中数组的最后一个位置是楼顶&#xff0c;但是根据第一个例子&#xff0c;如果最后一个位置是楼顶&#xff0c;花费最少应该为10&#xff0c;但是结果是15&#xff0c;因…

HCIP——堆叠技术实验配置

目录 一、堆叠的理论知识 二、堆叠技术实验配置 三、总结 一、堆叠的理论知识 1.1堆叠概述&#xff1a; 是指将两台交换机通过堆叠线缆连接在一起&#xff0c;从逻辑上变成一台交换设备&#xff0c;作为一个整体参与数据的转发。 1.2堆叠的基本概念 堆叠系统中所有的单台…

微软正在测试 Windows 11 对第三方密钥的支持

微软目前正在测试 WebAuthn API 更新&#xff0c;该更新增加了对使用第三方密钥提供商进行 Windows 11 无密码身份验证的支持。 密钥使用生物特征认证&#xff0c;例如指纹和面部识别&#xff0c;提供比传统密码更安全、更方便的替代方案&#xff0c;从而显著降低数据泄露风险…

ubuntu 安装proxychains

在Ubuntu上安装Proxychains&#xff0c;你可以按照以下步骤操作&#xff1a; 1、更新列表 sudo apt-update 2、安装Proxychains sudo apt-get install proxychains 3、安装完成后&#xff0c;你可以通过编辑/etc/proxychains.conf文件来配置代理规则 以下是一个简单的配置示例&…

数组学习后记——递归

数组这块学得有点乱,条理性欠佳。这次正好总结一下。上周的课堂内容没有更新, 因为小白自己也还没来得及吸收呢qwq。也解释一下为什么文中有这么多例题。因为我呢喜欢就着题去分析和学习,直接灌输知识不太能理解,有例子就能及时检验和应用了的。 先看看B3817 基础的双数组…

螺旋矩阵(java)

题目描述 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 代码思路&#xff1a; class Solution {public List<Integer> spiralOrder(int[][] matrix) {List<Integer> list new ArrayList<>(); …

【C#设计模式(16)——解释器模式(Interpreter Pattern)】

前言 解释器模式是用来解释和执行特定的语法或表达式。它将一种表达式的规则和语义进行抽象和封装&#xff0c;然后通过解释器来解析和执行这些规则&#xff0c;将其转化为可执行的操作。 代码 //抽象表达式public interface Expression{int Interpret(Context context); //解释…

OpenHarmony属性信息怎么修改?触觉智能RK3566鸿蒙开发板来演示

本文介绍在开源鸿蒙OpenHarmony系统下&#xff0c;修改产品属性信息的方法&#xff0c;触觉智能Purple Pi OH鸿蒙开发板演示&#xff0c;搭载了瑞芯微RK3566四核处理器&#xff0c;Laval鸿蒙社区推荐开发板&#xff0c;已适配全新OpenHarmony5.0 Release系统&#xff0c;感兴趣…

Python学习35天

# 定义父类 class Computer: CPUNone MemoryNone diskNone def __init__(self,CPU,Memory,disk): self.disk disk self.Memory Memory self.CPU CPU def get_details(self): return f"CPU:{self.CPU}\tdisk:{self.disk}\t…

基础入门-Web应用架构类别源码类别镜像容器建站模版编译封装前后端分离

知识点&#xff1a; 1、基础入门-Web应用-搭建架构上的技术要点 2、基础入门-Web应用-源码类别上的技术要点 一、演示案例-架构类别-模版&分离&集成&容器&镜像 1、套用模版型 csdn / cnblog / github / 建站系统等 安全测试思路上的不同&#xff1a; 一般…

数据库操作、锁特性

1. DML、DDL和DQL是数据库操作语言的三种主要类型 1.1 DML&#xff08;Data Manipulation Language&#xff09;数据操纵语言 DML是用于检索、插入、更新和删除数据库中数据的SQL语句。 主要的DML语句包括&#xff1a; SELECT&#xff1a;用于查询数据库中的数据。 INSERT&a…

七牛智能CDN视频优化方案,展现企业长期价值

随着智能设备和视频分享平台的日益普及,视频已成为现代人记录和分享生活不可或缺的方式。这一趋势不仅使得视频制作变得简单快捷,也促使视频内容在互联网上呈现爆炸式增长。然而,这一增长同时也为企业带来了诸多挑战,包括视频文件体积增大、加载速度受限、存储和传输成本提升,以…

Qt桌面应用开发 第八天(综合项目一 飞翔的鸟)

目录 1.鸟类创建 2.鸟动画实现 3.鼠标拖拽 4.自动移动 5.右键菜单 6.窗口透明化 项目需求&#xff1a; 实现思路&#xff1a; 创建项目导入资源鸟类创建鸟动画实现鼠标拖拽实现自动移动右键菜单窗口透明化 1.鸟类创建 ①鸟类中包含鸟图片、鸟图片的最小值下标和最大值…

云技术-docker

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团…

《解锁计算机专业宝藏:核心编程语言与学习资料全解析》

在当今数字化浪潮汹涌澎湃、技术迭代日新月异的时代&#xff0c;计算机专业宛如一座蕴藏无尽宝藏与无限机遇的神秘殿堂&#x1f3f0;。对于莘莘学子而言&#xff0c;精准掌握核心编程语言&#xff0c;并手握优质学习资料&#xff0c;恰似寻得开启这扇殿堂大门的秘钥&#xff0c…