设计模式 Day 4:观察者模式(Observer Pattern)深度解析
在经历了前三天的对象创建型设计模式学习之后,今天我们开始进入行为型设计模式的探索之旅。行为型模式聚焦于对象之间的通信机制与协作方式,其中最经典且应用最广泛的就是——观察者模式(Observer Pattern)。本文将用8000字篇幅,从设计哲学、模式原理、多语言实现到企业级应用,全方位解析这个"事件驱动编程基石"。
一、设计模式学习全景回顾
📜 Day 1~3 核心要点提炼
Day | 模式 | 核心思想 | 典型应用场景 | 实现难点 |
---|---|---|---|---|
1 | 单例模式 | 全局唯一实例访问控制 | 日志系统、配置中心 | 线程安全与双重检查锁定 |
2 | 工厂方法模式 | 将对象创建延迟到子类工厂 | 跨数据库驱动兼容 | 开闭原则的实践 |
3 | 抽象工厂模式 | 创建相关/依赖对象族 | 跨平台UI组件库 | 产品族扩展复杂度 |
知识链提示:前三天我们解决了对象创建的问题,今天开始处理对象行为的协调问题。
二、观察者模式深度剖析
📌 模式定义与本质
官方定义(GoF):
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
中文释义:
在对象间建立一种一对多的依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。
设计哲学:
- 松耦合原则:主题与观察者之间通过抽象接口交互
- 开闭原则:新增观察者无需修改主题代码
- 事件驱动架构:状态变化触发连锁反应
🌍 现实世界映射模型
场景1:新闻出版系统
- 出版社(Subject)发行新期刊
- 订阅用户(Observer)自动收到纸质刊物
- 新增订阅用户只需登记,无需修改出版社印刷流程
场景2:智能家居系统
- 温控传感器(Subject)检测到温度变化
- 空调、加湿器、手机App(Observers)同步响应
- 新设备接入只需注册监听,不影响传感器核心逻辑
场景3:电商库存预警
- 商品库存(Subject)数量变化
- 采购系统、营销系统、物流系统(Observers)触发对应操作
- 各系统独立升级不影响库存监控机制
三、模式结构全景透视
🧩 UML类图详解
@startuml
interface Subject {+ attach(Observer)+ detach(Observer)+ notify()
}interface Observer {+ update()
}class ConcreteSubject {- state: int+ getState(): int+ setState(int)
}class ConcreteObserverA {- subject: Subject+ update()
}class ConcreteObserverB {- subject: Subject+ update()
}Subject <|-- ConcreteSubject
Observer <|-- ConcreteObserverA
Observer <|-- ConcreteObserverB
ConcreteSubject o-- Observer : observers
ConcreteObserverA --> ConcreteSubject : subject
ConcreteObserverB --> ConcreteSubject : subject
@enduml
角色解析:
组件 | 职责说明 |
---|---|
Subject(抽象主题) | 定义添加、删除、通知观察者的接口 |
ConcreteSubject | 维护具体状态,状态变更时触发通知 |
Observer | 定义更新接口,用于接收主题通知 |
ConcreteObserver | 实现更新逻辑,可保存指向具体主题的引用以同步状态 |
⚙️ 工作原理时序图
@startuml
participant Client
participant ConcreteSubject
participant Observer1
participant Observer2Client -> ConcreteSubject: setState(newState)
ConcreteSubject -> ConcreteSubject: state = newState
ConcreteSubject -> ConcreteSubject: notify()
ConcreteSubject -> Observer1: update()
Observer1 -> ConcreteSubject: getState()
ConcreteSubject --> Observer1: currentState
ConcreteSubject -> Observer2: update()
Observer2 -> ConcreteSubject: getState()
ConcreteSubject --> Observer2: currentState
@enduml
四、多语言实现示例
🐍 Python 实现:气象站预警系统
from abc import ABC, abstractmethod
from typing import Listclass WeatherStation:"""具体主题:气象站"""def __init__(self):self._observers: List[WeatherObserver] = []self._temperature = 0.0def attach(self, observer: 'WeatherObserver') -> None:self._observers.append(observer)def detach(self, observer: 'WeatherObserver') -> None:self._observers.remove(observer)def notify(self) -> None:for observer in self._observers:observer.update(self)@propertydef temperature(self) -> float:return self._temperature@temperature.setterdef temperature(self, value: float) -> None:self._temperature = valueself.notify()class WeatherObserver(ABC):"""抽象观察者"""@abstractmethoddef update(self, subject: WeatherStation) -> None:passclass MobileApp(WeatherObserver):"""具体观察者:手机应用"""def update(self, subject: WeatherStation) -> None:print(f"Mobile App: 当前温度已更新至 {subject.temperature}°C")class TVDisplay(WeatherObserver):"""具体观察者:电视显示"""def update(self, subject: WeatherStation) -> None:print(f"TV Display: 温度变化提醒 → {subject.temperature}摄氏度")# 客户端调用
if __name__ == "__main__":station = WeatherStation()mobile = MobileApp()tv = TVDisplay()station.attach(mobile)station.attach(tv)station.temperature = 25.5station.temperature = 28.0station.detach(tv)station.temperature = 30.2
输出结果:
Mobile App: 当前温度已更新至 25.5°C
TV Display: 温度变化提醒 → 25.5摄氏度
Mobile App: 当前温度已更新至 28.0°C
TV Display: 温度变化提醒 → 28.0摄氏度
Mobile App: 当前温度已更新至 30.2°C
☕ Java 实现:拍卖竞价系统
import java.util.ArrayList;
import java.util.List;interface AuctionListener {void onBidAccepted(double price);
}class AuctionHouse {private final List<AuctionListener> listeners = new ArrayList<>();private double currentBid = 0.0;public void addListener(AuctionListener listener) {listeners.add(listener);}public void removeListener(AuctionListener listener) {listeners.remove(listener);}public void placeBid(double newBid) {if (newBid > currentBid) {currentBid = newBid;notifyListeners();}}private void notifyListeners() {for (AuctionListener listener : listeners) {listener.onBidAccepted(currentBid);}}
}class Bidder implements AuctionListener {private final String name;public Bidder(String name) {this.name = name;}@Overridepublic void onBidAccepted(double price) {System.out.printf("【%s】收到最新报价:%.2f元%n", name, price);}
}public class AuctionSystem {public static void main(String[] args) {AuctionHouse house = new AuctionHouse();Bidder bob = new Bidder("Bob");Bidder alice = new Bidder("Alice");house.addListener(bob);house.addListener(alice);house.placeBid(1000);house.placeBid(1500);house.removeListener(alice);house.placeBid(2000);}
}
运行结果:
【Bob】收到最新报价:1000.00元
【Alice】收到最新报价:1000.00元
【Bob】收到最新报价:1500.00元
【Alice】收到最新报价:1500.00元
【Bob】收到最新报价:2000.00元
五、模式变体与进阶应用
1. 推模型 vs 拉模型
类型 | 数据传递方式 | 优点 | 缺点 |
---|---|---|---|
推模型 | 主题将详细数据通过update参数推送 | 观察者无需主动请求数据 | 可能传递不需要的数据 |
拉模型 | 观察者从主题主动拉取所需数据 | 按需获取,减少数据传输量 | 增加主题与观察者的耦合度 |
推模型实现示例:
// 主题接口
class StockSubject {
public:virtual void notifyObservers(const std::string& symbol, float price) = 0;
};// 观察者接口
class StockObserver {
public:virtual void onPriceChanged(const std::string& symbol, float price) = 0;
};
拉模型实现示例:
class StockSubject {
public:virtual float getPrice(const std::string& symbol) const = 0;
};class StockObserver {
public:virtual void update(StockSubject* subject) = 0;
};
2. 线程安全观察者模式
多线程环境下的挑战:
- 观察者注册/注销时的竞态条件
- 通知过程中观察者列表的修改
- 观察者处理通知的线程阻塞
解决方案:
public class ConcurrentSubject {private final CopyOnWriteArrayList<Observer> observers = new CopyOnWriteArrayList<>();public void addObserver(Observer o) {observers.addIfAbsent(o);}public void notifyObservers() {for (Observer o : observers) {ExecutorService executor = Executors.newSingleThreadExecutor();executor.submit(() -> o.update(this));}}
}
3. 基于事件总线的全局观察者
架构示意图:
+---------------+ Event +-----------------+
| Publisher |------------->| Event Bus |
+---------------+ +-----------------+| ^| |v |+-----------------+| Subscriber |+-----------------+
TypeScript实现:
type Handler<T> = (event: T) => void;class EventBus {private handlers = new Map<string, Handler<any>[]>();on<T>(eventType: string, handler: Handler<T>) {const handlers = this.handlers.get(eventType) || [];handlers.push(handler);this.handlers.set(eventType, handlers);}emit<T>(eventType: string, event: T) {const handlers = this.handlers.get(eventType);handlers?.forEach(h => h(event));}
}// 使用示例
const bus = new EventBus();bus.on('auction:bid', (price: number) => {console.log(`New bid: $${price}`);
});bus.emit('auction:bid', 2500);
六、企业级应用案例分析
案例1:Spring Framework事件机制
核心组件:
ApplicationEvent
:所有应用事件的基类ApplicationListener
:观察者接口ApplicationEventPublisher
:主题角色
典型流程:
- 定义自定义事件:
public class OrderCreatedEvent extends ApplicationEvent {public OrderCreatedEvent(Order source) {super(source);}
}
- 发布事件:
@Autowired
ApplicationEventPublisher publisher;public void createOrder(Order order) {// ...业务逻辑publisher.publishEvent(new OrderCreatedEvent(order));
}
- 监听事件:
@Component
public class InventoryUpdateListener implements ApplicationListener<OrderCreatedEvent> {@Overridepublic void onApplicationEvent(OrderCreatedEvent event) {updateInventory(event.getOrder());}
}
案例2:Node.js EventEmitter
核心机制:
const EventEmitter = require('events');class MyEmitter extends EventEmitter {}const emitter = new MyEmitter();// 添加观察者
emitter.on('data', (chunk) => {console.log(`Received chunk: ${chunk}`);
});// 触发事件
setInterval(() => {emitter.emit('data', Date.now());
}, 1000);
高级特性:
- 一次性监听器:
emitter.once()
- 错误处理:
error
特殊事件 - 最大监听数限制:
emitter.setMaxListeners()
七、模式对比与选型指南
观察者模式 vs 发布订阅模式
维度 | 观察者模式 | 发布订阅模式 |
---|---|---|
耦合度 | 主题直接持有观察者引用 | 通过中间渠道完全解耦 |
通信方式 | 同步调用 | 通常异步消息队列 |
扩展性 | 适合简单场景 | 支持复杂路由和过滤 |
典型实现 | Java Observable | RabbitMQ、Kafka |
性能 | 高(直接调用) | 依赖中间件性能 |
适用场景 | 单进程内部通信 | 分布式系统、跨服务通信 |
与其他行为模式的关系
- 与中介者模式:都处理对象间通信,但中介者集中管理交互
- 与责任链模式:观察者广播通知,责任链顺序传递请求
- 与策略模式:观察者改变对象间交互方式,策略改变算法
八、今日练习题与详解
题目一:优化股票监控系统(进阶)
需求背景:
现有股票监控系统通知效率较低,需要实现:
- 支持按股票代码精确订阅
- 允许设置价格波动阈值(如TSLA波动超过5%才通知)
- 实现观察者优先级机制
参考实现:
class SmartStockServer:def __init__(self):self._subscriptions = defaultdict(dict) # {symbol: {observer: (threshold, priority)}}def subscribe(self, symbol, observer, threshold=0, priority=0):self._subscriptions[symbol][observer] = (threshold, priority)def unsubscribe(self, symbol, observer):del self._subscriptions[symbol][observer]def update_price(self, symbol, new_price):observers = self._subscriptions.get(symbol, {})sorted_observers = sorted(observers.items(),key=lambda x: -x[1][1] # 按优先级降序)for observer, (threshold, _) in sorted_observers:old_price = observer.last_prices.get(symbol, new_price)change = abs(new_price - old_price) / old_priceif change >= threshold:observer.update(symbol, new_price)
题目二:分布式观察者模式设计
场景需求:
设计一个跨微服务的订单状态变更通知系统,要求:
- 服务间完全解耦
- 支持动态增减订阅方
- 保证消息可靠性
架构方案:
- 使用 Kafka 作为消息中间件
- 定义统一事件协议(Protobuf/JSON Schema)
- 每个微服务作为独立Consumer Group
- 实现幂等处理防止重复消费
事件示例:
message OrderEvent {string event_id = 1;string order_id = 2;enum EventType {CREATED = 0;PAID = 1;SHIPPED = 2;COMPLETED = 3;}EventType type = 3;google.protobuf.Timestamp occurred_at = 4;map<string, string> metadata = 5;
}
九、总结与展望
观察者模式关键点回顾
- 核心价值:建立松耦合的对象间动态依赖关系
- 实现要点:
- 定义清晰的Subject-Observer接口
- 管理观察者注册机制
- 合理选择推/拉模型
- 适用场景:
- 事件驱动架构
- 跨模块状态同步
- 需要广播通知的场合
行业应用趋势
- 响应式编程:RxJS、Reactor等框架的观察者模式扩展
- Serverless架构:通过事件触发器实现函数调度
- 物联网领域:设备状态变更的实时同步
明日预告:策略模式(Strategy Pattern)—— 算法即对象,动态切换业务逻辑的核心技术。我们将深入探讨:
- 如何消除复杂的条件分支语句
- 支付系统多通道选择的最佳实践
- 与工厂模式的联合应用技巧
本文从基础到进阶,全面解析了观察者模式的设计哲学与实践应用。建议读者结合GitHub上的示例代码进行实战演练,同时思考如何在现有项目中应用该模式解决实际耦合问题。设计模式的学习需要理论与实践并重,才能真正内化为架构设计能力。
相关文章:
设计模式 Day 4:观察者模式(Observer Pattern)深度解析
在经历了前三天的对象创建型设计模式学习之后,今天我们开始进入行为型设计模式的探索之旅。行为型模式聚焦于对象之间的通信机制与协作方式,其中最经典且应用最广泛的就是——观察者模式(Observer Pattern)。本文将用8000字篇幅&a…...
`QTabWidget` 的标签页头设置样式,可以通过在 QSS 文件中定义 `QTabBar::tab` 的样式
要为 QTabWidget 的标签页头设置样式,可以通过在 QSS 文件中定义 QTabBar::tab 的样式来实现。以下是完整的代码示例和 QSS 文件内容,展示如何为标签页头设置背景颜色、文本颜色、悬停效果和选中效果。 ### **代码示例** cpp #include <QApplication…...
低代码开发革命:用 ZKmall开源商城可视化逻辑编排实现业务流程再造
ZKmall开源商城通过可视化逻辑编排引擎与低代码开发范式,重新定义了企业级电商业务流程的构建与优化方式。本文将从技术架构、核心能力、实践案例及行业价值等维度,解析其如何以"低代码流程引擎"组合拳实现业务流程再造的革命性突破。 一、低代…...
CAN外设
目录 1. CAN外设结构 1.1 CAN外设发送流程 1.2 CAN外设接收流程 1.3 发送接受配置位 2. CAN外设过滤器 2.1 过滤器配置 2.2 测试模式 2.3 工作模式 2.4 过滤器对应中断 2.5 错误处理和离线恢复 1. CAN外设结构 以STM32F103为例。以下是它的内部结构框图。 其具体发…...
(七)安卓开发中的状态列表图形(StateListDrawable)详解
在安卓开发中,**状态列表图形(StateListDrawable)**是一种非常实用的资源,它允许开发者根据视图的不同状态(如按下、聚焦、选中等)来动态显示不同的图像或颜色。这种机制在创建交互式用户界面时尤为重要&am…...
2023年蓝桥杯第十四届CC++大学B组真题及代码
目录 1A:日期统计 解析代码_暴力_正解 2B:01串的熵 解析代码_暴力_正解 3C:冶炼金属 解析代码_暴力_正解 4D:飞机降落 解析代码_暴力dfs_正解 5E:接龙数列 解析代码_dp_正解 6F:岛屿个数 解析代…...
odo18实施——销售-仓库-采购-制造-制造外包-整个流程自动化单据功能的演示教程
安装模块 安装销售 、库存、采购、制造模块 2.开启外包功能 在进入制造应用点击 配置—>设置 勾选外包,点击保存 添加信息 一、添加客户信息 点击到销售应用 点击订单—>客户 点击新建 创建客户1,及其他客户相关信息,点…...
c++造轮子之REACTOR实战
本文实现的为单reactor 多线程(base) 非核心库 InetAddress 这个库简单而言 无疑是设置ip地址和端口 class InetAddress { public:struct sockaddr_in addr;socklen_t addr_len;InetAddress();InetAddress(const char* ip, uint16_t port);~InetAddress(); };具体而言: Ine…...
【Easylive】Elasticsearch搜索组件详解
【Easylive】项目常见问题解答(自用&持续更新中…) 汇总版 一、Elasticsearch基础介绍 Elasticsearch(简称ES)是一个分布式、RESTful风格的搜索和分析引擎,基于Apache Lucene构建。在视频平台中,它主要用于: 全…...
基于AT89C51单片机的加减乘除液晶计算机设计
点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/90574816?spm1001.2014.3001.5503 功能介绍: 可进行最高四位数的加减乘除运算,除法运算保留小数点后四位;4*4矩阵按键输入&…...
先进制造aps专题三十三 开源aps产品,frepple和dream对比分析
开源的两个aps产品,frepple和dream对比分析 frepple开源的基本不能用,第一它甘特图没开源,而且甘特图不允许你手工个修改,你想把它当成手工甘特图用也不行,第二,算法强制倒排,很少企业是倒排 …...
Vue3.2 项目打包成 Electron 桌面应用
本文将详细介绍如何将基于 Vue3.2 的项目打包成 Electron 桌面应用。通过结合 Electron 和 Vue CLI 工具链,可以轻松实现跨平台桌面应用的开发与发布。 1. 项目结构说明 项目主要分为以下几个部分: electron/main.js:Electron 主进程文件。…...
第16届蓝桥杯单片机模拟试题Ⅰ
试题 代码 sys.h #ifndef __SYS_H__ #define __SYS_H__#include <STC15F2K60S2.H> //onewire.c float getT(); //sys.c extern unsigned char UI; extern bit touch_mode; extern float jiaozhun; extern float canshu; extern float temper; void init74hc138(unsigned…...
ES:geoip_databases
如何查看 .geoip_databases 的内容 在Elasticsearch中,.geoip_databases 是一个特殊的索引,用于存储GeoIP数据库文件。这些文件通常用于地理信息的丰富(GeoIP enrichment)。以下是如何查看和管理这些数据库文件的方法:…...
企业级开发SpringBoost玩转Elasticsearch
案例 Spring Boot 提供了 spring-data-elasticsearch 模块,可以方便地集成 Elasticsearch。 下面我们将详细讲解如何在 Spring Boot 中使用 Elasticsearch 8,并提供示例代码。 1. 添加依赖: 首先,需要在 pom.xml 文件中添加 spring-data-e…...
边缘计算网关作用
一、数据采集与预处理 边缘计算网关作为物联网系统的“数据入口”,能够连接各种传感器和设备,实时采集数据。在数据传输到云端之前,它会对数据进行清洗、过滤和聚合,剔除重复、无效或冗余的信息,只将有价值的数据上传…...
利用本地 Express Web 服务解决复杂的 Electron 通信链路的问题
背景 Web 服务对前端同学来说并不陌生,你们开发其他前端界面请求的后端接口就是 Web 服务,你们 npm run dev启动的也是一个本地的 Web 服务,前端的 js,html,css 都有从这个服务上拉取到的资源。 我们在开发 Electron…...
《自然-计算科学》诚邀您投稿计算社会科学研究(computational social science)
李升伟 编译 近年来,运用计算方法和工具来深化对社会科学长期议题理解的"计算社会科学"发展迅猛。这一增长主要得益于社交媒体数据、移动通信数据、数字化图书与历史档案、医疗记录等海量数据的涌现,这些资源不仅为验证现有社会科学理论提供了…...
【SPSS/EXCEl】主成分分析构建__综合评价指数
学习过程中实验操作的记录 1.数据准备和标准化: (1)区分正负相关性:判断每个因子是正向指标还是负向指标,计算每个的最大值和最小值 (2) 标准化: Min-Max标准化 Min-Max标准化(最大最小值法): 将数据映射到指定的区间ÿ…...
#node.js后端项目的部署相关了解
熟悉 Spring Boot 的 java -jar 启动方式,那咱们就用类比 实战方式,来彻底搞懂: 🚀 Node.js 后端项目的 部署 & 启动方式 ✅ 和 Spring Boot 的 java -jar xxx.jar 一样,Node.js 也可以一句命令启动,而…...
程序化广告行业(69/89):DMP与PCP系统核心功能剖析
程序化广告行业(69/89):DMP与PCP系统核心功能剖析 在数字化营销浪潮中,程序化广告已成为企业精准触达目标受众的关键手段。作为行业探索者,我深知其中知识的繁杂与重要性。一直以来,都希望能和大家一同学习…...
基于Python的二手房数据挖掘与可视化深度分析
一、技术框架与数据概况 1.1 技术栈构成 import pandas as pd # 数据操作(v1.3.5) import numpy as np # 数值计算(v1.21.6) from pyecharts.charts import * # 交互式可视化(v1.9.1) from sklearn.preprocessing import StandardScaler # 数据标准化(可选扩展) …...
linux第三次作业
1、将你的虚拟机的网卡模式设置为nat模式,给虚拟机网卡配置三个主机位分别为100、200、168的ip地址 2、测试你的虚拟机是否能够ping通网关和dns,如果不能请修改网关和dns的地址 3、将如下内容写入/etc/hosts文件中(如果有多个ip地址则写多行&…...
C#编写HttpClient爬虫程序示例
要写一个使用C#和HttpClient的爬虫程序。首先,我需要了解HttpClient的基本用法。HttpClient是用来发送HTTP请求和接收响应的类,对吧?我记得在C#中使用它的时候需要注意一些事情,比如最好使用单例实例,而不是频繁创建和…...
关于Spring MVC在无注解情况下通过参数名匹配获取请求参数的详细说明,包含代码示例和总结表格
以下是关于Spring MVC在无注解情况下通过参数名匹配获取请求参数的详细说明,包含代码示例和总结表格: 1. 核心机制 Spring MVC通过参数名匹配实现无注解参数绑定: 条件:方法参数名需与请求参数(查询参数、表单参数&a…...
数智读书笔记系列027:《医疗健康大数据治理》构建智慧医疗的核心基石
一、图书介绍: 1.1 书籍基本信息 在当今数字化技术飞速发展的背景下,医疗行业正经历着前所未有的变革。信息化、智能化、数据驱动的趋势正在深入到医疗服务的各个环节,推动着医疗健康大数据成为医疗行业发展的核心资产。在这样的时代背景下,《医疗健康大数据治理》这本书应…...
Wayland介绍
Wayland 是一种现代化的显示服务器协议,旨在替代传统的 X Window System(X11),为 Linux 和类 Unix 系统提供更高效、安全的图形显示管理。以下是其核心要点: 1. 基本概念 显示服务器协议:Wayland 定义了客户…...
dockerTeskTop安装dify及使用deepseek
配置 在这之前,要把模型运行一起,我这里是 PS C:\Users\Administrator> ollama run deepseek-r1:8b 模型名称一定要写对 如果添加失败,参考 dify 1.0.1无法在ollama下新增LLM模型 - 何辉煌 - 博客园...
解释 Git 的基本概念和使用方式
Git 是一个分布式版本控制系统,用于跟踪文件的变化并协作开发项目。下面是 Git 的一些基本概念和使用方式: 仓库(Repository):Git 仓库是用来存储项目文件的地方,可以在本地计算机上创建一个本地仓库&#…...
【区块链安全 | 第三十三篇】备忘单
文章目录 备忘单操作符优先级备忘单ABI 编码和解码函数bytes 和 string 的成员Address 的成员区块与交易属性校验和断言数学和加密函数合约相关类型信息函数可见性说明符修饰符备忘单 操作符优先级备忘单 以下是操作符的优先级顺序,按评估顺序列出: 优先级描述操作符1后缀递…...
MyBatis的缓存、逆向工程、使用PageHelper、使用PageHelper
一、MyBatis的缓存 缓存:cache 缓存的作用:通过减少IO的方式,来提高程序的执行效率。 mybatis的缓存:将select语句的查询结果放到缓存(内存)当中,下一次还是这条select语句的话,直…...
GS+:地统计分析与空间插值工具
大家好,今天为大家介绍的软件是GS:一款用于地统计分析与空间数据处理的软件。与ArcGIS相比的话,它更适合专注于地质统计学分析的用户,尤其是需要对半方差函数进行深入分析和调整的场景下面。我们将从软件的主要功能、支持的系统、…...
C++类型转换详解
目录 一、内置 转 内置 二、内置 转 自定义 三、自定义 转 内置 四、自定义 转 自定义 五、类型转换规范化 1.static_case 2.reinterpret_cast 3.const_cast 4.dynamic_cast 六、RTTI 一、内置 转 内置 C兼容C语言,在内置类型之间转换规则和C语言一样的&am…...
scala-集合2
可变数组 定义变长数组 val arr01 ArrayBuffer[Any](3, 2, 5) (1)[Any]存放任意数据类型 (2)(3, 2, 5)初始化好的三个元素 (3)ArrayBuffer 需要引入 scala.collection.mutable.ArrayBuffer 案例实操 Arra…...
Clang编译器优化选项
Clang 作为 C/C 编译器,提供了丰富的优化选项,以下是主要的优化相关选项分类和说明: 1. 优化级别(通用选项) 选项说明-O0默认级别,禁用所有优化,用于调试。-O1基础优化(代码大小和执…...
Java文件流操作 - 【Guava】IO工具
引言 Guava 使用术语 流来表示可关闭的,并且在底层资源中有位置状态的 I/O 数据流。字节流对应的工具类为 ByteSterams,字符流对应的工具类为 CharStreams。 Guava 中为了避免和流直接打交道,抽象出可读的 源 source 和可写的 汇 sink 两个概…...
C语言中单链表操作:查找节点与删除节点
一. 简介 前面学习了C语言中创建链表节点,向链表中插入节点等操作,文章如下: C语言中单向链表:创建节点与插入新节点-CSDN博客 本文继续学习c语言中对链表的其他操作,例如在链表中查找某个节点,删除链表…...
mapbox基础,加载栅格图片到地图
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️raster 栅格图层 api二、🍀使用本地载…...
Linux红帽:RHCSA认证知识讲解(十 二)调试 SELinux,如何管理 SELinux 的运行模式、安全策略、端口和上下文策略
Linux红帽:RHCSA认证知识讲解(十 二)调试 SELinux,如何管理 SELinux 的运行模式、安全策略、端口和上下文策略 前言一、SELinux 简介二、SELinux 的运行模式2.1 查看和切换 SELinux 模式 三、SELinux 预设安全策略的开关控制四、管…...
模糊斜率熵Fuzzy Slope entropy+状态分类识别!2024年11月新作登上IEEE Trans顶刊
引言 2024年11月,研究者在测量领域国际顶级期刊《IEEE Transactions on Instrumentation and Measurement》(IF 5.6,JCR 1区,中科院二区)上发表科学研究成果,以“Optimized Fuzzy Slope Entropy: A Comple…...
【MATLAB】将数据保存在mat文件中 save/load/matfile
MAT文件为MATLAB格式的二进制文件 save()函数 save - 将工作区变量保存到文件中 save(filename) 将当前工作区中的所有变量保存在 MATLAB 格式的二进制文件(MAT 文件)filename 中。如果 filename 已存在,save 会覆盖该文件。 save(filena…...
009_抽象类和接口
抽象类和接口 final关键字常量 单例模式(设计模式)枚举类抽象类抽象类的注意事项、特点使用抽象类的好处模版方法设计模式 接口接口的好处接口的注意事项 final关键字 final关键字是最终的意思,可以修饰类、方法、变量。 修饰类:…...
【数据结构】排序算法(下篇·开端)·深剖数据难点
前引:前面我们通过层层学习,也就了解了Hoare大佬的排序思想,今天我们学习的东西可能稍微有点难度,因此我们必须学会思想,我很受感慨,因此借此分享一下:【用1520分钟去调试】,如果我们…...
Elixir语言的计算机视觉
Elixir语言在计算机视觉中的应用 引言 计算机视觉作为一门交叉学科,近年来随着深度学习技术的发展而蓬勃发展。传统上,计算机视觉应用通常采用Python、C等语言进行开发,因为这些语言拥有强大的图像处理库和深度学习框架。然而,随…...
VTK知识学习(51)- 交互与Widget(二)
1、交互器样式 前面所讲的观察者/命令模式是 VTK实现交互的方式之一。在前面示例 所示的窗口中可以使用鼠标与柱体进行交互,比如用鼠标滚轮可以对柱体放大、缩小;按下鼠标左键不放,然后移动鼠标,可以转动柱体;按下鼠标左键,同时按…...
目标跟踪Deepsort算法学习2025.4.7
一.DeepSORT概述 1.1 算法定义 DeepSORT(Deep Learning and Sorting)是一种先进的多目标跟踪算法,它结合了深度学习和传统的目标跟踪技术,在复杂环境下实现了高精度和鲁棒性的目标跟踪。该算法的核心思想是通过融合目标的外观特征和运动特征,实现对多个目标的持续跟踪,…...
nacos集群启动问题
根据您的描述,Nacos集群只能启动两个节点,可能的原因和解决方法如下: 1. 集群配置问题 • 原因:cluster.conf文件中可能只配置了两个节点的地址,导致第三个节点无法加入集群。 • 解决方法: • 检查每个…...
八大排序——c++版
本次排序都是按照升序排的 冒泡排序 void bubbleSort(vector<int>& nums) {int nnums.size();for(int i0;i<n-1;i){bool swappedfalse;for(int j0;j<n-1-i;j){if(nums[j]>nums[j1]){swap(nums[j],nums[j1]);swappedtrue;}}if(!swapped)break;} } //算法原…...
关于Spring MVC中传递数组参数的详细说明,包括如何通过逗号分隔的字符串自动转换为数组,以及具体的代码示例和总结表格
以下是关于Spring MVC中传递数组参数的详细说明,包括如何通过逗号分隔的字符串自动转换为数组,以及具体的代码示例和总结表格: 1. 核心机制 Spring MVC支持直接通过逗号分隔的字符串将请求参数自动转换为数组(String[]、int[]等&…...
VBA之Word应用:利用Range方法进行字体及对齐方式设置
《VBA之Word应用》(版权10178982),是我推出第八套教程,教程是专门讲解VBA在Word中的应用,围绕“面向对象编程”讲解,首先让大家认识Word中VBA的对象,以及对象的属性、方法,然后通过实…...