C++软件设计模式之外观(Facade)模式
C++软件设计模式中的外观(Facade)模式
1. 外观模式的定义
外观模式(Facade Pattern)是一种结构型设计模式,它为一个复杂的子系统提供一个简化的接口。外观模式通过一个统一的接口来访问子系统的多个组成部分,使得客户端代码更加简单和易读。
2. 外观模式的主要意图
外观模式的主要意图是为复杂的子系统提供一个简单的接口,减少客户端代码与子系统之间的依赖关系,从而降低系统的复杂度。外观模式通过隐藏子系统的复杂性,使得客户端代码可以更专注于高层次的逻辑,而不需要关心底层实现的细节。
3. 外观模式的主要参与者
- Facade:提供一个简化的接口,客户端通过这个接口来访问子系统的多个组成部分。
- Subsystem Classes:复杂子系统的多个组成部分,每个子系统类都有自己的接口和实现。
4. 适用场合
外观模式适用于以下场合:
- 简化复杂的子系统:当一个子系统包含多个复杂的组件和接口时,可以通过外观模式提供一个简化的接口,隐藏子系统的复杂性。
- 提供统一的访问点:当需要为一组接口提供一个统一的访问点时,外观模式可以使得客户端代码更加简洁和易读。
- 降低依赖关系:通过外观模式,客户端代码可以减少对子系统内部组件的直接依赖,从而提高代码的可维护性和可扩展性。
- 分层系统设计:在分层系统设计中,高层模块可以通过外观模式访问低层模块,而不需要直接与低层模块的多个类打交道。
完整示例代码
假设我们有一个复杂的媒体库系统,包含多个子系统组件,如音频编码器、视频编码器和格式化器。我们可以通过外观模式来提供一个简化的接口,客户端代码可以通过这个接口来访问整个媒体库系统。
1. 子系统类
#include <iostream>
#include <string>class AudioEncoder {
public:void encodeAudio(const std::string& inputFile, const std::string& outputFile) {std::cout << "音频编码器: 将音频文件 " << inputFile << " 编码为 " << outputFile << std::endl;}
};class VideoEncoder {
public:void encodeVideo(const std::string& inputFile, const std::string& outputFile) {std::cout << "视频编码器: 将视频文件 " << inputFile << " 编码为 " << outputFile << std::endl;}
};class FileFormatter {
public:void formatFile(const std::string& inputFile, const std::string& outputFile) {std::cout << "文件格式化器: 将文件 " << inputFile << " 格式化为 " << outputFile << std::endl;}
};class MediaLibrary {
public:void downloadMedia(const std::string& mediaUrl, const std::string& downloadPath) {std::cout << "媒体库: 从 " << mediaUrl << " 下载媒体文件到 " << downloadPath << std::endl;}
};
2. 外观类
class MediaFacade {
private:AudioEncoder _audioEncoder;VideoEncoder _videoEncoder;FileFormatter _fileFormatter;MediaLibrary _mediaLibrary;
public:void processMedia(const std::string& mediaUrl, const std::string& outputDir) {std::string downloadPath = outputDir + "/downloaded_media.mp4";std::string encodedAudioPath = outputDir + "/encoded_audio.mp3";std::string encodedVideoPath = outputDir + "/encoded_video.mp4";std::string formattedPath = outputDir + "/formatted_media.mp4";// 下载媒体文件_mediaLibrary.downloadMedia(mediaUrl, downloadPath);// 编码音频_audioEncoder.encodeAudio(downloadPath, encodedAudioPath);// 编码视频_videoEncoder.encodeVideo(downloadPath, encodedVideoPath);// 格式化文件_fileFormatter.formatFile(encodedVideoPath, formattedPath);std::cout << "媒体处理完成: " << formattedPath << std::endl;}
};
3. 客户端代码
int main() {// 创建外观对象MediaFacade mediaFacade;// 处理媒体文件mediaFacade.processMedia("http://example.com/media/file.mp4", "/path/to/output");return 0;
}
代码讲解
-
子系统类:
AudioEncoder
:负责音频文件的编码。VideoEncoder
:负责视频文件的编码。FileFormatter
:负责文件的格式化。MediaLibrary
:负责从网络下载媒体文件。
-
外观类:
MediaFacade
:提供了一个简化的接口processMedia
,用于处理媒体文件。这个方法内部调用了子系统类的多个方法,完成了从下载、编码到格式化的一系列操作。- 方法:
processMedia(const std::string& mediaUrl, const std::string& outputDir)
- 接受媒体文件的URL和输出目录,调用子系统的各个组件来完成媒体文件的处理。
-
客户端代码:
- 创建
MediaFacade
对象。 - 调用
processMedia
方法来处理媒体文件,客户端代码只需要关注这个简单的接口,而不需要关心内部的复杂实现。
- 创建
适用场合的具体示例
-
简化复杂的子系统:
- 例如,一个多媒体处理系统可能包含多个子系统,如音频处理、视频处理、文件格式化等。通过外观模式,客户端代码只需要调用一个方法就可以完成多项复杂的处理,而不需要直接调用每个子系统的方法。
-
提供统一的访问点:
- 例如,一个网络应用可能需要与多个外部服务进行交互,如数据库、缓存、消息队列等。通过外观模式,可以提供一个统一的接口来管理这些外部服务的调用,使得客户端代码更加简洁。
-
降低依赖关系:
- 例如,一个软件系统可能依赖多个库或模块来完成某项任务。通过外观模式,可以隐藏这些库或模块的复杂性,使得客户端代码只需要依赖外观类,而不需要直接依赖每个库或模块。
-
分层系统设计:
- 例如,在一个分层的软件架构中,高层次模块可以通过外观模式访问低层次模块,而不需要直接与低层次模块的多个类打交道。
总结
外观模式通过提供一个简化的接口来访问复杂的子系统,减少了客户端代码与子系统之间的依赖关系,使得代码更加简洁和易读。这种模式特别适用于以下场合:
- 复杂子系统的简化:当子系统包含多个复杂的组件和接口时。
- 统一的访问点:当需要为一组接口提供一个统一的访问点时。
- 降低依赖关系:通过外观类隐藏子系统的复杂性,减少客户端代码的依赖。
- 分层系统设计:在分层的系统设计中,高层模块通过外观类访问低层模块。
Facade 模式的 UML 类图
Facade 模式通过提供一个简化的接口来封装一个复杂的子系统。下面是一个 Facade 模式的 UML 类图示例:
+-----------------+ +-----------------+
| Client | | Facade |
|-----------------| |-----------------|
| - main() | | - SubsystemA |
| <------------+>| - SubsystemB |
| - processMedia() || - SubsystemC |
| || - ... |
| |+-----------------+
| || - processMedia()|
+-----------------+ +-----------------+|v
+-----------------+ +-----------------+ +-----------------+ +-----------------+
| SubsystemA | | SubsystemB | | SubsystemC | | ... |
|-----------------| |-----------------| |-----------------| |-----------------|
| - encodeAudio() | | - encodeVideo() | | - formatFile() | | - ... |
+-----------------+ +-----------------+ +-----------------+ +-----------------+
UML 类图解释
-
Client:
- 职责:客户端类,使用外观类来访问复杂的子系统。
- 方法:
main()
:客户端的主方法,调用外观类的processMedia()
方法来处理媒体文件。processMedia()
:客户端通过外观类调用的方法,用于处理媒体文件。
-
Facade:
- 职责:外观类,提供一个简化的接口来访问子系统的多个组件。
- 属性:
SubsystemA
:持有子系统A的实例。SubsystemB
:持有子系统B的实例。SubsystemC
:持有子系统C的实例。...
:可以有更多子系统的实例。
- 方法:
processMedia()
:外观类提供的方法,内部调用子系统的多个方法来完成复杂操作。
-
SubsystemA:
- 职责:子系统A类,负责某一特定任务(例如音频编码)。
- 方法:
encodeAudio()
:执行音频编码的逻辑。
-
SubsystemB:
- 职责:子系统B类,负责另一特定任务(例如视频编码)。
- 方法:
encodeVideo()
:执行视频编码的逻辑。
-
SubsystemC:
- 职责:子系统C类,负责另一特定任务(例如文件格式化)。
- 方法:
formatFile()
:执行文件格式化的逻辑。
-
其他子系统:
- 职责:可以有更多的子系统类,每个子系统类都有自己的接口和实现。
详细解释
1. 客户端类(Client)
- Client 类是使用外观模式的客户端代码。
- 方法
main()
和processMedia()
:客户端通过这些方法调用外观类Facade
的processMedia()
方法来处理媒体文件。客户端不需要关心具体的子系统实现细节,只需要使用外观类提供的简化接口。
2. 外观类(Facade)
- Facade 类是外观模式的核心,它提供了一个简化的接口来访问子系统的多个组件。
- 属性:外观类持有一个或多个子系统的实例,这些实例可以通过构造函数或setter方法进行初始化。
- 方法
processMedia()
:这个方法内部调用子系统的多个方法来完成复杂的操作。例如,处理媒体文件可能需要从网络下载、编码音频、编码视频、格式化文件等步骤,这些步骤都由外观类的processMedia()
方法统一管理。
3. 子系统类(SubsystemA, SubsystemB, SubsystemC, …)
- 子系统类 负责具体的任务,每个子系统类都有自己的接口和实现。
- 方法:子系统类的方法执行具体的任务,如音频编码、视频编码、文件格式化等。
- 职责分离:子系统类之间的职责是分离的,每个子系统类都专注于自己的任务。
Facade 模式、Adapter 模式和 Mediator 模式的相似之处和不同之处
1. 相似之处
-
简化接口:
- Facade 模式、Adapter 模式 和 Mediator 模式 都通过提供一个简化的接口来简化复杂系统的使用。
- 它们的目的都是为了减少客户端代码的复杂度,使得客户端代码更加简洁和易读。
-
封装细节:
- 这三种模式都通过封装子系统的复杂性来隐藏内部的实现细节。
- 客户端代码只需要关注高层次的接口,而不需要关心底层的具体实现。
2. 重要不同点
-
Facade 模式:
- 目的:为一个复杂的子系统提供一个简化的接口。
- 适用场合:当一个子系统包含多个复杂的组件和接口时,通过外观模式提供一个统一的接口来简化客户端的使用。
- 实现方式:外观类通常拥有多个子系统的实例,并通过组合这些子系统的方法来实现高层次的逻辑。
- 关系:外观类和子系统类之间的关系是组合(Composition),外观类通过内部持有的子系统类实例来调用子系统的方法。
- 示例:媒体处理系统中的外观类
MediaFacade
提供了一个简单的processMedia
方法来调用多个子系统的方法,完成从下载到格式化的一系列操作。
-
Adapter 模式:
- 目的:将一个类的接口转换成客户端期望的另一个接口。
- 适用场合:当客户端代码需要与一个已有但接口不兼容的类进行交互时,通过适配器模式来实现接口的转换。
- 实现方式:适配器类通常通过继承或包含一个已有类来实现接口的转换。
- 关系:适配器类和被适配的类之间的关系可以是继承(Inheritance)或组合(Composition)。
- 示例:将一个旧的音频播放器类的接口转换成新的音频播放器接口,使得客户端代码可以无缝地使用新的音频播放器。
// 旧的音频播放器接口 class OldAudioPlayer { public:void playSound(const std::string& filename) {std::cout << "旧音频播放器: 播放 " << filename << std::endl;} };// 新的音频播放器接口 class NewAudioPlayer { public:virtual void play(const std::string& filename) = 0; };// 适配器类,实现了新的音频播放器接口 class AudioAdapter : public NewAudioPlayer { private:OldAudioPlayer _oldPlayer; public:void play(const std::string& filename) override {_oldPlayer.playSound(filename);} };// 客户端代码 int main() {std::unique_ptr<NewAudioPlayer> player = std::make_unique<AudioAdapter>();player->play("example.mp3");return 0; }
-
Mediator 模式:
- 目的:通过一个中介者对象来封装多个对象之间的交互,降低对象之间的耦合度。
- 适用场合:当多个对象之间存在复杂的相互依赖关系时,通过中介者模式来管理这些依赖关系,使得对象之间的交互更加简单和可控。
- 实现方式:中介者类管理多个对象的交互,每个对象都通过中介者类来通信,而不是直接与其他对象通信。
- 关系:中介者类和子对象之间的关系是双向的,子对象通过中介者类来通信,中介者类管理子对象之间的交互。
- 示例:在一个图形用户界面中,多个窗口和按钮之间的交互可以通过一个中介者类来管理。
#include <iostream> #include <memory> #include <vector>// 中介者接口 class Mediator { public:virtual ~Mediator() {}virtual void send(const std::string& message, Component* sender) = 0; };// 组件接口 class Component { protected:Mediator* _mediator; public:Component(Mediator* mediator) : _mediator(mediator) {}virtual ~Component() {}virtual void send(const std::string& message) = 0;virtual void receive(const std::string& message) = 0; };// 具体组件A class ComponentA : public Component { public:ComponentA(Mediator* mediator) : Component(mediator) {}void send(const std::string& message) override {_mediator->send(message, this);}void receive(const std::string& message) override {std::cout << "组件A收到消息: " << message << std::endl;} };// 具体组件B class ComponentB : public Component { public:ComponentB(Mediator* mediator) : Component(mediator) {}void send(const std::string& message) override {_mediator->send(message, this);} void receive(const std::string& message) override {std::cout << "组件B收到消息: " << message << std::endl;} };// 具体中介者 class ConcreteMediator : public Mediator { private:std::vector<std::unique_ptr<Component>> _components; public:void addComponent(std::unique_ptr<Component> component) {_components.push_back(std::move(component));}void send(const std::string& message, Component* sender) override {for (auto& component : _components) {if (component.get() != sender) {component->receive(message);}}} };// 客户端代码 int main() {ConcreteMediator mediator;auto componentA = std::make_unique<ComponentA>(&mediator);auto componentB = std::make_unique<ComponentB>(&mediator);mediator.addComponent(std::move(componentA));mediator.addComponent(std::move(componentB));// 组件A发送消息mediator._components[0]->send("Hello, componentB!");return 0; }
重要不同点总结
-
Facade 模式:
- 作用:提供一个简化的接口来访问复杂子系统的多个组件。
- 关系:外观类与子系统类之间是组合关系。
- 适用场合:当一个子系统包含多个复杂的组件和接口时,通过外观模式提供一个统一的接口。
-
Adapter 模式:
- 作用:将一个类的接口转换成客户端期望的另一个接口。
- 关系:适配器类与被适配的类之间可以是继承或组合关系。
- 适用场合:当客户端代码需要与一个已有但接口不兼容的类进行交互时。
-
Mediator 模式:
- 作用:通过一个中介者对象来封装多个对象之间的交互,降低对象之间的耦合度。
- 关系:中介者类与子对象之间是双向关系,子对象通过中介者类来通信。
- 适用场合:当多个对象之间存在复杂的相互依赖关系时,通过中介者模式来管理这些依赖关系。
关键区别
- Facade 提供一个高层的、简化的接口来访问多个子系统的组件,客户端只需要与外观类交互。
- Adapter 将一个类的接口转换为客户期望的接口,通常用于适配不同的类或库。
- Mediator 管理多个对象之间的交互,使得对象之间的依赖关系更加松散,减少了对象之间的直接通信。
Facade 模式在分层软件架构中的作用
1. 分层软件架构简介
分层软件架构通常将一个系统划分为多个层次(或层级),每个层次负责不同的职责。常见的分层结构包括:
- 表示层(Presentation Layer):与用户交互,处理用户界面逻辑。
- 业务逻辑层(Business Logic Layer):处理业务逻辑和数据处理。
- 数据访问层(Data Access Layer):与数据库或其他数据存储进行交互。
- 外部服务层(External Services Layer):与其他系统或服务进行交互。
2. Facade 模式在分层软件架构中的作用
在分层软件架构中,Facade 模式通常用于提供一个高层次的、简化的接口,使得上层模块可以更方便地访问下层模块。具体作用包括:
- 简化高层模块的访问:通过外观类,高层模块可以使用一个简单的接口来访问底层模块的多个复杂组件,不需要关注底层的实现细节。
- 降低耦合度:高层模块与底层模块之间的依赖关系通过外观类来管理,降低了耦合度,方便维护和扩展。
- 模块化设计:外观类可以作为一个模块的入口点,使得系统的模块化设计更加清晰。
3. 具体示例
假设我们有一个三层架构的电子商务系统,分为表示层、业务逻辑层和数据访问层。
- 表示层:处理用户界面逻辑,如显示商品列表、购物车等。
- 业务逻辑层:处理业务逻辑,如订单处理、库存管理等。
- 数据访问层:与数据库进行交互,获取和存储数据。
我们可以在业务逻辑层中使用 Facade 模式来提供一个简化的接口,使得表示层可以更方便地访问业务逻辑层。
业务逻辑层(子系统)
#include <iostream>
#include <string>class OrderService {
public:void placeOrder(const std::string& userId, const std::string& productId, int quantity) {// 订单处理逻辑std::cout << "订单服务: 为用户 " << userId << " 下单 " << quantity << " 个 " << productId << std::endl;}
};class InventoryService {
public:void checkInventory(const std::string& productId, int quantity) {// 库存检查逻辑std::cout << "库存服务: 检查 " << productId << " 的库存,数量为 " << quantity << std::endl;}
};class PaymentService {
public:void processPayment(const std::string& userId, const std::string& orderId, int amount) {// 支付处理逻辑std::cout << "支付服务: 为用户 " << userId << " 处理订单 " << orderId << " 的支付,金额为 " << amount << std::endl;}
};
业务逻辑层的外观类
class BusinessFacade {
private:OrderService _orderService;InventoryService _inventoryService;PaymentService _paymentService;
public:void processPurchase(const std::string& userId, const std::string& productId, int quantity, int amount) {// 检查库存_inventoryService.checkInventory(productId, quantity);// 下单std::string orderId = "ORDER123"; // 假设订单ID_orderService.placeOrder(userId, productId, quantity);// 处理支付_paymentService.processPayment(userId, orderId, amount);}
};
表示层(客户端代码)
int main() {BusinessFacade facade;std::string userId = "USER123";std::string productId = "PROD456";int quantity = 2;int amount = 100;// 处理购买操作facade.processPurchase(userId, productId, quantity, amount);return 0;
}
代码解释
-
业务逻辑层的子系统类:
OrderService
:负责处理订单逻辑。InventoryService
:负责检查库存逻辑。PaymentService
:负责处理支付逻辑。
-
业务逻辑层的外观类:
BusinessFacade
:提供一个简化的接口processPurchase
,用于处理购买操作。这个方法内部调用了OrderService
、InventoryService
和PaymentService
的多个方法,完成了从检查库存到处理支付的一系列操作。- 属性:
_orderService
、_inventoryService
和_paymentService
,这些属性是子系统类的实例。
-
表示层(客户端代码):
- 创建
BusinessFacade
对象。 - 调用
processPurchase
方法来处理购买操作,表示层代码只需要关注这个简单的接口,而不需要关心内部的复杂实现。
- 创建
Facade 模式在微服务系统中的作用
1. 微服务架构简介
微服务架构将一个应用程序拆分为多个小型、独立的服务,每个服务负责特定的业务功能。这些服务通常通过网络进行通信,可以独立部署和扩展。
2. Facade 模式在微服务系统中的作用
在微服务系统中,Facade 模式可以用于提供一个统一的接口来访问多个微服务,具体作用包括:
- 简化客户端访问:通过外观类,客户端可以使用一个简单的接口来访问多个微服务,而不需要直接与每个微服务进行通信。
- 降低耦合度:客户端与微服务之间的依赖关系通过外观类来管理,降低了耦合度,方便维护和扩展。
- 统一异常处理和日志记录:外观类可以统一处理异常和日志记录,使得客户端代码更加简洁和易读。
3. 具体示例
假设我们有一个微服务系统,包含订单服务、库存服务和支付服务。
订单服务
#include <iostream>
#include <string>class OrderService {
public:std::string placeOrder(const std::string& userId, const std::string& productId, int quantity) {// 订单处理逻辑std::cout << "订单服务: 为用户 " << userId << " 下单 " << quantity << " 个 " << productId << std::endl;return "ORDER123"; // 假设订单ID}
};
库存服务
class InventoryService {
public:bool checkInventory(const std::string& productId, int quantity) {// 库存检查逻辑std::cout << "库存服务: 检查 " << productId << " 的库存,数量为 " << quantity << std::endl;return true; // 假设库存充足}
};
支付服务
class PaymentService {
public:void processPayment(const std::string& userId, const std::string& orderId, int amount) {// 支付处理逻辑std::cout << "支付服务: 为用户 " << userId << " 处理订单 " << orderId << " 的支付,金额为 " << amount << std::endl;}
};
微服务系统的外观类
class MicroserviceFacade {
private:std::unique_ptr<OrderService> _orderService;std::unique_ptr<InventoryService> _inventoryService;std::unique_ptr<PaymentService> _paymentService;
public:MicroserviceFacade() : _orderService(std::make_unique<OrderService>()), _inventoryService(std::make_unique<InventoryService>()), _paymentService(std::make_unique<PaymentService>()) {}void processPurchase(const std::string& userId, const std::string& productId, int quantity, int amount) {// 检查库存if (!_inventoryService->checkInventory(productId, quantity)) {std::cout << "库存不足,无法完成购买" << std::endl;return;}// 下单std::string orderId = _orderService->placeOrder(userId, productId, quantity);// 处理支付_paymentService->processPayment(userId, orderId, amount);std::cout << "购买操作完成: " << orderId << std::endl;}
};
客户端代码
int main() {MicroserviceFacade facade;std::string userId = "USER123";std::string productId = "PROD456";int quantity = 2;int amount = 100;// 处理购买操作facade.processPurchase(userId, productId, quantity, amount);return 0;
}
代码解释
-
微服务类:
OrderService
:负责处理订单逻辑,返回订单ID。InventoryService
:负责检查库存逻辑,返回库存是否充足。PaymentService
:负责处理支付逻辑。
-
微服务系统的外观类:
MicroserviceFacade
:提供一个简化的接口processPurchase
,用于处理购买操作。这个方法内部调用了OrderService
、InventoryService
和PaymentService
的多个方法,完成了从检查库存到处理支付的一系列操作。- 属性:
_orderService
、_inventoryService
和_paymentService
,这些属性是微服务类的实例。 - 方法:
processPurchase
- 接受用户ID、产品ID、数量和金额,调用微服务的各个组件来完成购买操作。
-
客户端代码:
- 创建
MicroserviceFacade
对象。 - 调用
processPurchase
方法来处理购买操作,客户端代码只需要关注这个简单的接口,而不需要关心内部的复杂实现。
- 创建
总结
-
分层软件架构中的 Facade 模式:
- 作用:提供一个高层次的、简化的接口,使得上层模块可以更方便地访问下层模块。
- 优点:简化高层模块的访问,降低耦合度,模块化设计更加清晰。
-
微服务系统中的 Facade 模式:
- 作用:提供一个统一的接口来访问多个微服务,简化客户端的访问逻辑。
- 优点:简化客户端访问,降低耦合度,统一异常处理和日志记录。
通过 Facade 模式,无论是分层软件架构还是微服务系统,都可以有效地隐藏复杂性,提供更简洁和易用的接口,从而提高系统的可维护性和可扩展性。希望这些解释能帮助你更好地理解 Facade 模式在不同场景中的应用。
相关文章:
C++软件设计模式之外观(Facade)模式
C软件设计模式中的外观(Facade)模式 1. 外观模式的定义 外观模式(Facade Pattern)是一种结构型设计模式,它为一个复杂的子系统提供一个简化的接口。外观模式通过一个统一的接口来访问子系统的多个组成部分࿰…...
Spring Boot 项目创建
创建一个新项目: 打开 Spring Initializr 网址:https://start.spring.io/ ,然后创建一个新项目: springboot3.3.5_jdk17: Project(Maven)编程语言(Java 17)Spring Boo…...
SharpDX 从入门到精通:全面学习指南
摘要: 本文旨在为想要深入学习 SharpDX 的开发者提供一份全面的指南。从 SharpDX 的基础概念入手,逐步深入探讨其在不同场景下的应用,包括图形渲染、音频处理等,并结合大量详细的代码案例帮助读者更好地理解和掌握 SharpDX 的使用…...
【Web】2024“国城杯”网络安全挑战大赛决赛题解(全)
最近在忙联通的安全准入测试,很少有时间看CTF了,今晚抽点时间回顾下上周线下的题(期末还没开始复习😢) 感觉做渗透测试一半的时间在和甲方掰扯&水垃圾洞,没啥惊喜感,还是CTF有意思 目录 Mountain ez_zhuawa 图…...
操作系统(24)提高磁盘I/O速度的途径
前言 操作系统提高磁盘I/O速度的途径多种多样,这些途径旨在减少磁盘访问的延迟和开销,提高数据传输的效率。 一、磁盘高速缓存(Disk Cache) 磁盘高速缓存是一种在内存中为磁盘数据设置的缓冲区,用于存储磁盘中某些盘块…...
en3d 部署笔记
目录 依赖项: Nvdiffrast 编译代码和frpc_linux_amd64 下载地址: tiny-cuda-nn 安装 ICON算法库依赖 icon依赖 kaolin infer_normal_fixpose 解决 报错了,推荐的安装方法: kaolin测试: ICON依赖项 requirements.txt 改进 voxelize_cuda 安装ok 运行后: 修改代…...
c++类型判断和获取原始类型
std::traits学习 类型判断和退化(获取原始类型)的原理就是利用模板的特例化。根据调用模板的特例化,在特例化模板中实现判断的逻辑或者退化的逻辑。 一、类型判断 判断整型数据的模板类 #include <iostream> namespace zk {templa…...
医疗行业 UI 设计系列合集(一):精准定位
在当今数字化时代,医疗行业与信息技术的融合日益紧密,UI 设计在其中扮演着至关重要的角色。精准定位的 UI 设计能够显著提升医疗产品与服务的用户体验,进而对医疗效果和患者满意度产生积极影响。 一、医疗行业 UI 设计的重要性概述 医疗行业…...
EasyExcel停更,FastExcel接力
11月6日消息,阿里巴巴旗下的Java Excel工具库EasyExcel近日宣布,将停止更新,未来将逐步进入维护模式,将继续修复Bug,但不再主动新增功能。 EasyExcel以其快速、简洁和解决大文件内存溢出的能力而著称,官方…...
java agent的使用【通俗易懂版】
一、静态代理Agent 1.生成Agent的jar包 (1)创建Agent项目,引入javassist.jar包 (2)编写premain方法 import java.lang.instrument.Instrumentation;public class Agent1 {public static void premain(Stri…...
010 Qt_输入类控件(LineEdit、TextEdit、ComboBox、SpinBox、DateTimeEdit、Dial、Slider)
文章目录 前言一、QLineEdit1.简介2.常见属性及说明3.重要信号及说明4.示例一:用户登录界面5.示例二:验证两次输入的密码是否一致显示密码 二、TextEdit1.简介2.常见属性及说明3.重要信号及说明4.示例一:获取多行输入框的内容5.示例二&#x…...
C++设计模式:享元模式 (附文字处理系统中的字符对象案例)
什么是享元模式? 享元模式是一个非常实用的结构型设计模式,它的主要目的是节省内存,尤其在需要创建大量相似对象时。 通俗解释: 想象我们在写一本书,每个字母都需要表示出来。如果每个字母都单独用对象表示ÿ…...
机器学习之 KNN 算法
一、引言 在机器学习领域中,K 近邻(K-Nearest Neighbors,KNN)算法是一种简单而有效的分类和回归算法。它的基本思想是根据数据点之间的距离来确定它们的相似性,并根据其最近的邻居的类别或数值来预测新数据点的类别或…...
矩阵:Input-Output Interpretation of Matrices (中英双语)
矩阵的输入-输出解释:深入理解与应用 在线性代数中,矩阵与向量的乘积 ( y A x y Ax yAx ) 是一个极为重要的关系。通过这一公式,我们可以将矩阵 ( A A A ) 看作一个将输入向量 ( x x x ) 映射到输出向量 ( y y y ) 的线性变换。在这种…...
ctfhub技能树——disable_functions
LD_PRELOAD 来到首页发现有一句话直接就可以用蚁剑连接 根目录里有/flag但是不能看;命令也被ban了就需要绕过了 绕过工具在插件市场就可以下载 如果进不去的话 项目地址: #本地仓库;插件存放 antSword\antData\plugins 绕过选择 上传后我们点进去可以看到多了一个绕过的文件;…...
Web3.0安全开发实践:探索比特币DeFi生态中的PSBT
近年来,部分签名比特币交易(PSBT)在比特币生态系统中获得了显著关注。随着如Ordinal和基于铭文的资产等创新的兴起,安全的多方签名和复杂交易的需求不断增加,这使得PSBT成为应对比特币生态不断发展中不可或缺的工具。 …...
【Yonghong 企业日常问题 06】上传的文件不在白名单,修改allow.jar.digest属性添加允许上传的文件SH256值?
文章目录 前言问题描述问题分析问题解决1.允许所有用户上传驱动文件2.如果是想只上传白名单的驱动 前言 该方法适合永洪BI系列产品,包括不限于vividime desktop,vividime z-suit,vividime x-suit产品。 问题描述 当我们连接数据源的时候&a…...
Lecture 6 Isolation System Call Entry
文章目录 一 重要的函数清单1 write(user/usys.s) 一 usertrap函数(C code) Lecture6 Isolation & System Call Entry视频链接 对应XV6 Book Chapter 4 Traps and device drivers 一 重要的函数清单 1 write(user/usys.s) .global write write:li a7, SYS_writeecallret…...
重温设计模式----装饰模式
文章目录 装饰模式定义UML 图其主要优点包括:装饰模式的主要角色有:C 代码示例总结 装饰模式定义 动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式必生成子类更加灵活 装饰模式(Decorator Pattern&…...
图像处理-Ch2-空间域的图像增强
Ch2 空间域的图像增强 文章目录 Ch2 空间域的图像增强Background灰度变换函数(Gray-level Transformation)对数变换(Logarithmic)幂律变换(Power-Law)分段线性变换函数(Piecewise-Linear)对比度拉伸(Contrast-Stretching)灰度级分层(Gray-level Slicing) 直方图处理(Histogram …...
uniapp Native.js原生arr插件服务发送广播到uniapp页面中
前言 最近搞了个设备,需求是读取m1卡,厂家给了个安卓原生demo,接入arr插件如下,接入后发现还是少了一部分代码,设备服务调起后触发刷卡无法发送到uniapp里。 中间是一些踩坑记录,最后面是解决办法…...
重温设计模式--1、组合模式
文章目录 1 、组合模式(Composite Pattern)概述2. 组合模式的结构3. C 代码示例4. C示例代码25 .应用场景 1 、组合模式(Composite Pattern)概述 定义:组合模式是一种结构型设计模式,它允许你将对象组合成…...
关于鸿蒙架构feature
鸿蒙feature层模块架构 model:定义数据类型,进行接口请求 view:视图层 写UI viewModel:控制层 关于逻辑和请求调用 page页...
CentOS下,离线安装vscode的步骤;
前置条件: 1.CentOS7; 步骤: 1.下载vscode指定版本,例如; 例如 code-1.83.1-1696982959.el7.x86_64.rpm 2.使用下面命令: sudo rpm -ivh code-1.83.1-1696982959.el7.x86_64.rpm 其他: 卸载vscode的命…...
.NET周刊【12月第3期 2024-12-15】
国内文章 重磅推出 Sdcb Chats:一个全新的开源大语言模型前端 https://www.cnblogs.com/sdcb/p/18597030/sdcb-chats-intro Sdcb Chats是一个新推出的开源大语言模型前端,旨在提升用户交互体验,并填补市场上基于.NET的前端空白。它引入树状…...
操作系统(23)外存的存储空间的管理
一、外存的基本概念与特点 定义:外存,也称为辅助存储器,是计算机系统中用于长期存储数据的设备,如硬盘、光盘、U盘等。与内存相比,外存的存储容量大、成本低,但访问速度相对较慢。特点:外存能够…...
vue3中多层级路由缓存失效问题
问题现象: 在项目中路由嵌套了超过两层后,使用keep-alive对路由进行页面的缓存,发现并不能生效。 使用的路由结构: // 一级路由path: menu1,component: () > import(/views/demos/nested/menu1/index), // Parent router-vie…...
Kerberoasting 离线爆破攻击
当域用户请求某个域内服务后,kdc 通常会返回一个加密的 st 服务票据,此 st 服务票据被服务 hash 加密,当我们将使用密码字典派生的多个 hash 值来尝试解密 st 服务票据,如果能够揭秘成功,则说明字典中存在目标服务账号…...
无人机双目视觉鲁棒定位方法!
无人机双目视觉鲁棒定位方法是一种先进的定位技术,它利用两个摄像头(即双目相机)模拟人的视觉系统,通过视差来确定物体的位置。这种方法在无人机定位领域具有广泛的应用前景,特别是在GPS信号拒止或弱纹理环境中&#x…...
vulnhub靶场——Log4j2
第一步:搭建靶场环境 #开启环境 cd vulhub/log4j/CVE-2021-44228 docker-compose up -d 来到网站首页 第二步:搭建一个dnslog平台上获取我们注入的效果 第三步:发现 /solr/admin/cores?action 这里有个参数可以传 我们可以看到留下了访问记录并且前面的参数被执行后给我们回…...
第十六章 C++ 字符串
C 字符串 C 提供了以下两种类型的字符串表示形式: C 风格字符串C 引入的 string 类类型 C 风格字符串 C 风格的字符串起源于 C 语言,并在 C 中继续得到支持。字符串实际上是使用 null 字符 终止的一维字符数组。因此,一个以 null 结尾的…...
centos权限大集合,覆盖多种权限类型,解惑权限后有“. + t s”问题!
在 CentOS 系统中,权限管理是操作系统的核心功能之一,确保不同用户和进程对文件、目录以及设备的访问被合理控制。 权限系统主要包括传统的 Unix 权限模型、特殊权限(SetUID、SetGID、Sticky 位)和更精细的访问控制列表ÿ…...
【k8s】访问etcd
1. 配置 export.sh export ETCDCTL_API3 # Kubernetes 1.13 使用 API v3 export ETCDCTL_ENDPOINTShttps://[2023:145:246:270::3]:2379 # etcd API endpoint,通常为集群内的 etcd 服务地址 export ETCDCTL_CACERT/etc/kubernetes/certs/ca.crt # CA 证书文件 …...
【教程宝典】基于“遥感+”蓝碳储量估算、红树林信息提取实践技术应用与科研论文写作
“遥感”助推蓝碳生态系统碳储量调查简介(1)蓝碳生态系统碳储量研究背景 红树林、海草床和盐沼是海岸带最具固碳效率的三大生态系统,统称为“蓝色碳汇”。虽然这三类生态系统的覆盖面积不到海床的0.5%,植物生物量只占陆地植物生物量的0.05%,…...
运动健康中的实体和关系
1. 实体类别 1.1 个人健康相关实体 个人(Person):参与体育活动的个体,如运动员、健身爱好者、患者等。健康状况(HealthStatus):描述个人的身体状态,如体重、血压、心率、身体质量指…...
【进阶编程】MVC和MVVM实现前后端分离的实现
在 WPF 开发中,通常使用 MVVM(Model-View-ViewModel)架构来分离视图和业务逻辑,但在某些情况下,你可能希望将 MVC(Model-View-Controller)模式与 MVVM 结合使用。这种结合有时是为了兼顾不同的架…...
ML-Agents 概述(二)
注:本文章为官方文档翻译,如有侵权行为请联系作者删除 ML-Agents Overview - Unity ML-Agents Toolkit–原文链接 ML-Agents 概述(一) ML-Agents 概述(二) 训练方法:特定环境 除了上一节介绍的…...
[Unity] ShaderGraph动态修改Keyword Enum,实现不同效果一键切换
上次更新已然四个月前,零零散散的工作结束,终于有时间写点东西记录一下~ 实际使用中,经常会碰到同一个对象需要切换不同的材质,固然可以通过C#直接替换材质球。 或者在ShaderGraph中使用Comparison配合Branch实现切换ÿ…...
国自然面上项目分享|基于人工智能和病理组学的早癌筛查算法研究|基金申请·24-12-24
小罗碎碎念 今天分享的项目为【常规面上项目】,执行年限为2018年1月至2021年12月,直接费用为55万元。 今天分享的这个项目很有意思,因为这个项目的成果是团队2020年申报基金委优青的材料,并且还有临床验证和商业转化,值…...
【EthIf-14】EthIfGeneral容器配置-02
1.实际EthIfGeneral的配置实例 关闭DET接口开启发送确认中断开启接收中断主周期接收timeout主周期 2. 代码实例参考 阅读此部分代码,搞清楚代码分为几个section,大概瞄一眼就好,不用深究其含义,只需有一个宏观的层次结构的映像即可。 //Appl/GenData/EthIf_Cfg.h #...
21.打印文件地址 C#例子
\是一个有特殊功能的字符,当想要打印一个如下地址时, C:\Users\SMTC\source\repos\练习 会出现报错,之所以会报错就是因为这里出现了\ \可以把后面的一个符号变为真符号,而不是有特殊功能的符号 在字符串的前面可以让这个字符…...
golang LeetCode 热题 100(动态规划)-更新中
爬楼梯 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 示例 1:输入:n 2 输出:2 解释:有两种方法可以爬到楼顶。 1. 1 阶 1 阶 2. 2 阶 示例 2&…...
Everspin代理MR25H10CDFR存储MRAM
RAMSUN提供的MR25H10CDFR是一款具备1,048,576位存储容量的磁阻随机存取存储器(MRAM)设备,由131,072个8位字构成。该设备提供与串行EEPROM和串行闪存兼容的读/写时序,无写延迟,并且其读/写寿命是不受限制的。 与其它串…...
Day13 苍穹外卖项目 工作台功能实现、Apache POI、导出数据到Excel表格
目录 1.工作台 1.1 需求分析和设计 1.1.1 产品原型 1.1.2 接口设计 1.2 代码导入 1.2.1 Controller层 1.2.2 Service层接口 1.2.3 Service层实现类 1.2.4 Mapper层 1.3 功能测试 1.4 代码提交 2.Apache POI 2.1 介绍 2.2 入门案例 2.2.1 将数据写入Excel文件 2.2.2 读取Excel文…...
基于vue框架的的校园后台报修管理系统设计与实现u7fui(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
系统程序文件列表 项目功能:用户,维修工,报修信息,维修情况,评价记录,请假记录,改派申请记录 开题报告内容 基于Vue框架的校园后台报修管理系统设计与实现开题报告 一、项目背景及意义 随着信息技术的飞速发展,校园管理日益趋向于智能化和高效化。传…...
TCP/IP 模型中,网络层对 IP 地址的分配与路由选择
TCP/IP 模型中,网络层对 IP 地址的分配与路由选择 一. IP 地址的分配1.1 IP 地址的结构与分类1.2 IP 地址的分配方式 二. 路由选择2.3 路由协议2.4 路由表的结构2.5 路由选择的算法2.6 默认路由与静态路由 三. 网络层的 IP 地址分配与路由选择总结 前言 这是我在这个…...
废品回收小程序:助力企业转型发展
废品回收在当下日常生活中非常常见,家中的各种可回收物都能够拿到回收站进行回收,减少浪费,不过在回收物较多的情况下,回收又成为了一个问题。 目前,随着智能生活的流行,废品回收开启了“数字化时代”&…...
iptables交叉编译(Hisiav300平台)
参考文章:https://blog.csdn.net/Bgm_Nilbb/article/details/135714738 https://bbs.archlinux.org/viewtopic.php?pid1701065 1、libmnl 交叉编译 tar xvf libmnl-1.0.5.tar.bz2 sudo chmod 777 -R libmnl-1.0.5 cd libmnl-1.0.5 mkdir _install //host和CC需要修…...
概率论 期末 笔记
第一章 随机事件及其概率 利用“四大公式”求事件概率 全概率公式与贝叶斯公式 伯努利概型求概率 习题 推导 一维随机变量及其分布 离散型随机变量(R.V)求分布律 利用常见离散型分布求概率 连续型R.V相关计算 利用常见连续型分布的计算 均匀分布 正态…...
【Chrome】浏览器提示警告Chrome is moving towards a new experience
文章目录 前言一、如何去掉 前言 Chrome is moving towards a new experience that allows users to choose to browse without third-party cookies. 这是谷歌浏览器(Chrome)关于隐私策略更新相关的提示 提示:以下是本篇文章正文内容&…...