设计模式(七)

迭代器模式(Iterator Pattern)详解

一、核心概念

迭代器模式提供一种方法来顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。该模式将遍历逻辑封装在迭代器对象中,使聚合对象和遍历逻辑分离。

核心组件

  1. 迭代器接口(Iterator):定义访问和遍历元素的方法。
  2. 具体迭代器(Concrete Iterator):实现迭代器接口,跟踪聚合对象中的当前位置。
  3. 聚合接口(Aggregate):定义创建迭代器对象的方法。
  4. 具体聚合(Concrete Aggregate):实现聚合接口,返回一个具体迭代器实例。
二、代码示例:自定义集合迭代器

场景:实现一个简单的数组集合,并为其提供迭代器支持。

#include <iostream>
#include <memory>// 前向声明
template<typename T> class ArrayIterator;// 迭代器接口
template<typename T>
class Iterator {
public:virtual ~Iterator() = default;virtual bool hasNext() const = 0;virtual T& next() = 0;virtual const T& next() const = 0;
};// 聚合接口
template<typename T>
class Aggregate {
public:virtual ~Aggregate() = default;virtual std::unique_ptr<Iterator<T>> createIterator() const = 0;virtual size_t size() const = 0;virtual T& operator[](size_t index) = 0;virtual const T& operator[](size_t index) const = 0;
};// 具体聚合:数组集合
template<typename T, size_t N>
class Array : public Aggregate<T> {
private:T data[N];size_t count = 0;public:void add(const T& item) {if (count < N) {data[count++] = item;}}size_t size() const override { return count; }T& operator[](size_t index) override { return data[index]; }const T& operator[](size_t index) const override { return data[index]; }std::unique_ptr<Iterator<T>> createIterator() const override;
};// 具体迭代器:数组迭代器
template<typename T, size_t N>
class ArrayIterator : public Iterator<T> {
private:const Array<T, N>* array;size_t position;public:explicit ArrayIterator(const Array<T, N>* array) : array(array), position(0) {}bool hasNext() const override {return position < array->size();}T& next() override {return (*array)[position++];}const T& next() const override {return (*array)[position++];}
};// 实现createIterator方法
template<typename T, size_t N>
std::unique_ptr<Iterator<T>> Array<T, N>::createIterator() const {return std::make_unique<ArrayIterator<T, N>>(this);
}// 客户端代码
int main() {Array<int, 5> numbers;numbers.add(10);numbers.add(20);numbers.add(30);// 使用迭代器遍历集合auto it = numbers.createIterator();while (it->hasNext()) {std::cout << it->next() << " ";}std::cout << std::endl;// C++范围for循环风格(需额外实现begin/end)// 此处省略具体实现...return 0;
}
三、迭代器模式的优势
  1. 分离遍历逻辑

    • 聚合对象的结构与遍历逻辑分离,符合单一职责原则。
  2. 简化聚合接口

    • 聚合类无需提供复杂的遍历接口,仅需创建迭代器。
  3. 支持多种遍历方式

    • 同一聚合对象可支持多种迭代器(如正向、反向、过滤迭代器)。
  4. 统一访问接口

    • 客户端通过统一的迭代器接口访问不同聚合结构,提高代码通用性。
四、实现变种
  1. 内部迭代器 vs 外部迭代器

    • 外部迭代器(如示例):客户端控制迭代过程。
    • 内部迭代器:迭代逻辑由迭代器自身控制,客户端提供回调函数。
  2. 双向迭代器

    • 支持向前和向后遍历(如 prev() 方法)。
  3. 流式迭代器

    • 支持惰性计算,适用于大数据集(如数据库查询结果)。
  4. 组合迭代器

    • 遍历组合模式中的树形结构(如文件系统)。
五、适用场景
  1. 隐藏聚合实现

    • 当需要隐藏聚合对象的内部结构(如数组、链表、树)时。
  2. 支持多种遍历方式

    • 如顺序遍历、随机访问、过滤遍历等。
  3. 统一遍历接口

    • 为不同类型的聚合对象提供一致的遍历接口。
  4. 简化客户端代码

    • 使客户端无需关心聚合对象的具体类型,专注于元素处理。
六、注意事项
  1. 迭代器失效

    • 在迭代过程中修改聚合对象可能导致迭代器失效(如删除元素)。
  2. 线程安全

    • 在多线程环境中,需确保迭代器的线程安全性。
  3. 与语言特性结合

    • C++ 标准库已提供 std::iterator 和容器迭代器,优先使用现有实现。
  4. 性能开销

    • 间接访问可能带来性能开销,需根据场景优化。
七、与其他模式的对比
  1. 与访问者模式的区别

    • 迭代器模式专注于遍历,访问者模式专注于元素处理。
  2. 与组合模式的结合

    • 组合模式的树形结构常使用迭代器模式遍历。
  3. 与生成器模式的关系

    • 生成器模式可用于动态生成迭代器所需的元素。

迭代器模式是处理聚合对象遍历的经典解决方案,通过将遍历逻辑封装在迭代器中,使代码更简洁、灵活且易于维护。在实际开发中,建议优先使用编程语言提供的内置迭代器(如 C++ 的 STL 迭代器),避免重复造轮子。

单例模式(Singleton Pattern)详解

一、核心概念

单例模式确保一个类只有一个实例,并提供一个全局访问点来获取该实例。该模式常用于需要全局唯一对象的场景,如配置管理器、日志记录器、数据库连接池等。

核心组件

  1. 私有构造函数:防止外部直接实例化。
  2. 静态实例:持有类的唯一实例。
  3. 静态访问方法:提供全局访问点。
二、代码示例
1. 懒汉式(Lazy Initialization)
// 线程不安全版本(单线程环境)
class Singleton {
private:static Singleton* instance;Singleton() = default;             // 私有构造函数~Singleton() = default;            // 私有析构函数Singleton(const Singleton&) = delete;         // 禁用拷贝构造Singleton& operator=(const Singleton&) = delete; // 禁用赋值运算符public:static Singleton* getInstance() {if (instance == nullptr) {     // 第一次调用时初始化instance = new Singleton();}return instance;}
};// 静态成员初始化
Singleton* Singleton::instance = nullptr;
2. 线程安全的懒汉式(双检锁)
#include <mutex>class Singleton {
private:static Singleton* instance;static std::mutex mutex_;Singleton() = default;public:static Singleton* getInstance() {if (instance == nullptr) {     // 第一次检查std::lock_guard<std::mutex> lock(mutex_);if (instance == nullptr) { // 第二次检查(锁内)instance = new Singleton();}}return instance;}
};Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mutex_;
3. 饿汉式(Eager Initialization)
class Singleton {
private:static const Singleton* instance;Singleton() = default;public:static const Singleton* getInstance() {return instance;}
};// 静态初始化(在main函数前完成)
const Singleton* Singleton::instance = new Singleton();
4. C++11 标准的 Meyers’ Singleton(推荐)
class Singleton {
private:Singleton() = default;~Singleton() = default;Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;public:static Singleton& getInstance() {static Singleton instance;     // 线程安全的局部静态变量return instance;}
};
三、单例模式的优势
  1. 全局唯一性

    • 确保系统中一个类只有一个实例,便于资源控制。
  2. 全局访问点

    • 提供统一的访问方式,无需传递对象引用。
  3. 延迟初始化

    • 懒汉式实现支持延迟加载,节省资源。
  4. 严格控制访问

    • 通过私有构造函数和静态方法,严格控制实例化过程。
四、实现变种
  1. 多线程安全

    • 使用双检锁(DCLP)或 C++11 的局部静态变量保证线程安全。
  2. 可销毁单例

    • 添加静态销毁方法,确保正确释放资源。
  3. 模板单例

    • 使用模板实现通用单例基类,支持多个类复用单例逻辑。
  4. 参数化单例

    • 在首次调用时传入参数初始化单例。
五、适用场景
  1. 资源管理器

    • 如数据库连接池、文件系统管理器。
  2. 配置管理

    • 全局配置信息的读写。
  3. 日志系统

    • 集中记录系统运行状态。
  4. GUI 组件

    • 如窗口管理器、对话框工厂。
六、注意事项
  1. 线程安全

    • 在多线程环境下必须保证实例创建的原子性(如 Meyers’ Singleton)。
  2. 内存泄漏

    • 动态分配的实例需确保正确释放(可使用智能指针或静态局部变量)。
  3. 反序列化问题

    • 单例类需防止通过反序列化创建新实例。
  4. 继承与多态

    • 单例类的子类可能导致多个实例,需谨慎设计。
七、与其他模式的对比
  1. 与静态类的区别

    • 单例是对象,支持继承和多态;静态类是全局方法集合。
  2. 与工厂模式的结合

    • 单例可作为工厂模式的工厂,创建其他对象。
  3. 与享元模式的区别

    • 单例强调唯一实例,享元强调对象复用。

单例模式是解决全局唯一对象需求的经典方案,但需谨慎使用,避免滥用导致代码耦合度高。在现代 C++ 中,推荐使用 Meyers’ Singleton 实现,既简洁又安全。

合成/聚合复用原则(CARP)详解

一、核心概念

合成/聚合复用原则(Composition/Aggregation Reuse Principle, CARP)主张:
“要尽量使用合成/聚合,而不是类继承来达到复用的目的”

  • 合成(Composition):强拥有关系,部分与整体生命周期一致(如std::unique_ptr)。
  • 聚合(Aggregation):弱拥有关系,部分可独立于整体存在(如std::shared_ptr或引用)。

该原则强调通过对象组合实现复用,而非通过继承扩展类功能,以降低代码耦合度。

二、合成/聚合 vs 继承
维度合成/聚合(推荐)继承(需谨慎)
耦合度低(对象间松耦合)高(子类依赖父类实现)
灵活性运行时动态组合,支持多态编译时静态绑定,难以修改
复用粒度细粒度(复用具体组件)粗粒度(复用整个父类)
依赖可见性仅依赖接口,不暴露内部实现可能暴露父类非公共接口
设计模式策略模式、装饰器模式、组合模式模板方法模式、工厂方法模式
三、代码示例:交通工具与引擎
1. 反例:使用继承复用(高耦合)
// 父类:引擎
class Engine {
public:void start() { std::cout << "引擎启动" << std::endl; }void stop() { std::cout << "引擎停止" << std::endl; }
};// 子类:汽车(继承引擎)
class Car : public Engine {
public:void drive() {start();  // 直接复用父类方法std::cout << "汽车行驶" << std::endl;stop();}
};// 子类:飞机(继承引擎)
class Plane : public Engine {
public:void fly() {start();  // 直接复用父类方法std::cout << "飞机起飞" << std::endl;stop();}
};

问题

  • 继承导致CarPlaneEngine强绑定,无法在运行时更换引擎类型。
  • Engine修改接口,所有子类需同步修改。
2. 正例:使用聚合复用(低耦合)
// 接口:引擎
class IEngine {
public:virtual void start() = 0;virtual void stop() = 0;virtual ~IEngine() = default;
};// 具体引擎:燃油引擎
class GasolineEngine : public IEngine {
public:void start() override { std::cout << "燃油引擎启动" << std::endl; }void stop() override { std::cout << "燃油引擎停止" << std::endl; }
};// 具体引擎:电动引擎
class ElectricEngine : public IEngine {
public:void start() override { std::cout << "电动引擎启动" << std::endl; }void stop() override { std::cout << "电动引擎停止" << std::endl; }
};// 交通工具(聚合引擎)
class Vehicle {
private:std::unique_ptr<IEngine> engine;  // 聚合:组合关系public:explicit Vehicle(std::unique_ptr<IEngine> engine) : engine(std::move(engine)) {}void setEngine(std::unique_ptr<IEngine> newEngine) {engine = std::move(newEngine);}void operate() {engine->start();std::cout << "交通工具运行" << std::endl;engine->stop();}
};// 客户端代码
void clientCode() {// 使用燃油引擎auto car = Vehicle(std::make_unique<GasolineEngine>());car.operate();// 动态更换为电动引擎car.setEngine(std::make_unique<ElectricEngine>());car.operate();
}

优势

  • 通过聚合IEngine接口,Vehicle与具体引擎实现解耦。
  • 支持运行时动态切换引擎类型,符合开闭原则。
四、合成/聚合复用的典型场景
  1. 策略模式(Strategy Pattern)
    通过组合不同策略对象实现算法切换:

    class SortStrategy {
    public:virtual void sort(std::vector<int>& data) = 0;
    };class QuickSort : public SortStrategy { /* 实现 */ };
    class MergeSort : public SortStrategy { /* 实现 */ };class Sorter {
    private:std::unique_ptr<SortStrategy> strategy;
    public:void setStrategy(std::unique_ptr<SortStrategy> s) {strategy = std::move(s);}void performSort(std::vector<int>& data) {strategy->sort(data);}
    };
    
  2. 装饰器模式(Decorator Pattern)
    通过组合增强对象功能:

    class Component {
    public:virtual void operation() = 0;
    };class ConcreteComponent : public Component { /* 基础实现 */ };class Decorator : public Component {
    protected:std::shared_ptr<Component> component;
    public:explicit Decorator(std::shared_ptr<Component> c) : component(c) {}
    };class LoggingDecorator : public Decorator {
    public:void operation() override {std::cout << "Before operation" << std::endl;component->operation();std::cout << "After operation" << std::endl;}
    };
    
五、使用指南
  1. 优先使用合成/聚合的场景

    • 需要动态改变对象行为时(如策略模式)。
    • 复用细粒度组件而非整个类时。
    • 避免继承导致的“脆弱基类问题”(修改基类可能破坏子类)。
  2. 继承的合理场景

    • 当子类是基类的“自然扩展”(如正方形是矩形的特例)。
    • 复用基类的不变部分,扩展可变部分(如模板方法模式)。
    • 实现多态接口(如抽象工厂模式)。
  3. 黄金法则

    • “HAS-A”关系优先用组合/聚合(如汽车引擎)。
    • “IS-A”关系谨慎用继承(如正方形矩形)。
六、注意事项
  1. 过度组合导致的问题

    • 可能增加对象数量和管理复杂度。
    • 需合理设计接口,避免接口膨胀。
  2. 与依赖倒置原则(DIP)结合

    • 聚合对象应依赖抽象接口而非具体实现,进一步降低耦合。
  3. 继承的替代方案

    • 委托(Delegation):通过对象组合实现行为委托。
    • 混入(Mixin):通过模板或多重继承复用特定功能。

合成/聚合复用原则是实现低耦合、高内聚设计的关键,它通过对象组合替代继承,使系统更灵活、可维护和可扩展。在设计时,应根据具体场景权衡继承与组合的使用,避免过度依赖单一复用方式。

在C++中,无法在运行时动态确定子类继承自哪个基类。这是因为C++的继承关系是静态绑定的,必须在编译时明确指定。不过,你可以通过以下几种方式模拟运行时选择基类的行为

一、为什么不能在运行时确定继承关系?

  1. 编译时确定内存布局
    子类的内存布局(包括基类子对象的偏移量)在编译时必须确定,否则无法进行对象访问。

  2. 静态类型系统限制
    C++的类型系统要求在编译时明确类的继承结构,以保证类型安全。

二、替代方案

1. 组合(Composition)替代继承

思路:在子类中包含基类指针,运行时动态选择基类实现。

#include <memory>// 基接口
class Base {
public:virtual void doSomething() = 0;virtual ~Base() = default;
};// 具体实现类A
class ConcreteA : public Base {
public:void doSomething() override { /* 实现A */ }
};// 具体实现类B
class ConcreteB : public Base {
public:void doSomething() override { /* 实现B */ }
};// 动态选择行为的类
class DynamicClass {
private:std::unique_ptr<Base> strategy;  // 组合基类指针public:// 在运行时设置行为void setStrategy(std::unique_ptr<Base> strategy) {this->strategy = std::move(strategy);}// 委托调用void performAction() {if (strategy) strategy->doSomething();}
};// 运行时选择示例
void runtimeSelection(bool condition) {DynamicClass obj;if (condition) {obj.setStrategy(std::make_unique<ConcreteA>());} else {obj.setStrategy(std::make_unique<ConcreteB>());}obj.performAction();  // 根据condition选择不同实现
}
2. 模板(编译时多态)

思路:通过模板参数在编译时选择基类。

// 基类A
class BaseA {
public:void method() { /* 基类A的实现 */ }
};// 基类B
class BaseB {
public:void method() { /* 基类B的实现 */ }
};// 模板子类:编译时选择基类
template<typename BaseType>
class Derived : public BaseType {
public:void callBaseMethod() {this->method();  // 调用所选基类的方法}
};// 编译时选择示例
void compileTimeSelection(bool condition) {if (condition) {Derived<BaseA> obj;  // 继承自BaseAobj.callBaseMethod();} else {Derived<BaseB> obj;  // 继承自BaseBobj.callBaseMethod();}
}
3. 多重继承 + 运行时类型切换

思路:继承所有可能的基类,运行时通过接口选择具体行为。

// 接口A
class InterfaceA {
public:virtual void actionA() = 0;
};// 接口B
class InterfaceB {
public:virtual void actionB() = 0;
};// 实现类同时继承两个接口
class MultiBase : public InterfaceA, public InterfaceB {
public:void actionA() override { /* 实现A */ }void actionB() override { /* 实现B */ }
};// 运行时选择接口
void runtimeInterfaceSelection(bool useA) {MultiBase obj;if (useA) {InterfaceA* ptr = &obj;ptr->actionA();  // 使用接口A} else {InterfaceB* ptr = &obj;ptr->actionB();  // 使用接口B}
}
4. 动态加载插件(运行时动态绑定)

思路:通过插件系统在运行时加载不同的实现库。

// 公共接口
class PluginInterface {
public:virtual void execute() = 0;virtual ~PluginInterface() = default;
};// 插件工厂(简化版)
class PluginFactory {
public:static std::unique_ptr<PluginInterface> createPlugin(const std::string& name) {// 实际实现中通过动态库加载if (name == "A") return std::make_unique<PluginA>();if (name == "B") return std::make_unique<PluginB>();return nullptr;}
};// 运行时加载插件
void loadPluginAtRuntime(const std::string& pluginName) {auto plugin = PluginFactory::createPlugin(pluginName);if (plugin) plugin->execute();
}

三、各方案对比

方案实现方式绑定时机灵活性复杂度
组合替代继承持有基类指针运行时
模板模板参数选择基类编译时
多重继承继承所有基类,选接口使用运行时
动态加载插件运行时加载动态库运行时极高

四、总结

  • C++无法真正实现运行时继承,因为继承关系必须在编译时确定。
  • 组合(策略模式)是最常用的替代方案,它通过委托机制在运行时动态选择行为。
  • 模板方案适用于编译时已知的选择,可提供零成本抽象。
  • 动态加载插件则适用于需要最大灵活性的场景(如插件系统)。

根据具体需求,选择合适的替代方案来模拟“运行时选择基类”的行为。

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

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

相关文章

24年OPPO秋季笔试题

257. 小欧过河 链接&#xff1a;https://kamacoder.com/problempage.php?pid1337 思路&#xff1a;这道题的实际需要求的就是在两个11之间&#xff0c;最多能有多少个0。可以记录在遍历序列的时候&#xff0c;记录有最多个0的1的两个下标&#xff0c;最后再返回其差值。要注…

处理Lombok的一个小BUG

对于Lombok报错的修改 一、问题描述 在使用IDEA创建spring boot项目时如果你勾选了Lombok&#xff0c;生成的Lombok会随着maven的刷新而改变处理器的扫描路径&#xff0c;从项目类变到自定义的处理器路径 二、原因与解决方法 原因就是这里写了Lombok的路径才会导致你每次刷新都…

【Java入门到精通】(一)Java发展历程与环境搭建指南

一、Java的发展 Java是在1991年由SUN公司的James Gosling&#xff08;Java之父&#xff09;及其团队所研发的一种编程语言&#xff0c;第一个版本耗时18个月&#xff0c;最开始命名为Oak&#xff08;一种橡树&#xff09;。Java现在广泛应用于各种大型互联网应用&#xff0c;其…

【RK3568+PG2L50H开发板实验例程】Linux部分/UAR读写案例

本原创文章由深圳市小眼睛科技有限公司创作&#xff0c;版权归本公司所有&#xff0c;如需转载&#xff0c;需授权并注明出处&#xff08;www.meyesemi.com) 1.1. 案例简介 本案例旨在介绍如何测试开发板上的 UART 串口通信功能。 开发板支持的串口及其对应的设备节点如下表所…

Webpack 中的 Loader 和 Plugin 全面详解

&#x1f3af; Webpack 中的 Loader 和 Plugin 全面详解 &#x1f4cc; 整理不易&#xff0c;记得收藏、点赞再加关注&#xff0c;后续还会更新更多实战文档&#xff01; Webpack 是现代前端构建体系的核心工具&#xff0c;其中 Loader 和 Plugin 是其功能扩展的两大支柱。它们…

主流分布式中间件及其选型

分布式架构中的中间件技术 在互联网公司的分布式架构中&#xff0c;中间件是支撑系统高可用、高并发、可扩展的核心组件。这些中间件针对分布式环境下的共性问题&#xff08;如通信、数据一致性、资源调度等&#xff09;提供标准化解决方案&#xff0c;极大降低了分布式系统的…

设备需求极致紧凑的空间体验,我们该如何解决?

在自动化集成过程&#xff0c;往往会碰到设备对控制系统体积有极致要求的情况&#xff0c;面对这样的挑战&#xff0c;如何解决&#xff1f; 项目背景与需求分析 在自动化集成过程&#xff0c;往往会碰到设备对控制系统体积有极致要求的情况&#xff0c;面对这样的挑战&#x…

Kotlin扩展函数与属性

扩展函数和属性是Kotlin中最具特色的功能之一&#xff0c;它们允许我们在不修改原有类的情况下为类添加新功能。这种设计既保持了类的封装性&#xff0c;又提供了强大的扩展能力。 一、扩展函数&#xff1a;为现有类添加新行为 1.1 基础扩展函数 扩展函数允许我们为任何类&am…

厨师上门做饭小程序源码php方案

厨师上门做饭小程序源码&#xff0c;开发语言后端php&#xff0c;前端uniapp。可二开定制 三个端&#xff1a;用户端师傅端小程序&#xff0c;pc管理后台。 一 用户端 1.单点大厨&#xff1a;选择厨师预约下单&#xff0c;查看厨师评价、厨师的套餐。 2.点套餐&#xff1a;选择…

LLM大模型如何访问MySQL业务数据库

目录 一、LLM大模型如何访问MySQL业务数据库 1.1 为什么需要SQL Agent? 1.2 什么是 create_sql_agent&#xff1f; 1.3 什么是SQLDatabaseToolkit? 二、SQL Agent智能体操作MySQL数据库 三、本地启动服务 验证效果 四、怎么提高SQL Agent智能体的回复准确性&#xff1…

MySQL(112)如何选择读写分离策略?

选择读写分离策略是实施读写分离的关键一步。常见的读写分离策略包括简单的读写分离和基于负载均衡的读写分离。为了实现这些策略&#xff0c;我们需要动态地选择数据源。下面详细介绍如何实现基于Spring Boot的读写分离&#xff0c;并结合代码示例展示不同策略的实现。 读写分…

日志-解决Linux因target is busy无法卸载硬盘/分区的问题 - PHP持续占用分区

效果图 写在前面 此次遇到的问题是&#xff0c;php-fpm持续占用设备/mnt/disk1&#xff0c;强制杀死php所有进程后&#xff0c;依然会自动产生新的进程再次霸占分区&#xff0c;导致设备无法卸载umount。思路是解决谁在不停的捣乱。 步骤 核心&#xff1a; 挂载文件系统到指定…

Linux系统权限维持篇

Openssh后门 重新安装自定义的openssh&#xff0c;达到记录账户密码&#xff0c;也可以采用万能密码连接的功能 1、登录方式 2、登录软件 3、登录机制 环境准备 yum -y install openssl openssl-devel pam-devel zlib zlib-devel yum -y install gcc gcc-c makewget http://c…

spring中maven缺少包如何重新加载,报错java: 程序包org.springframework.web.reactive.function不存在

错误原因分析 java: 程序包org.springframework.web.reactive.function不存在 这个错误是由于 项目中缺少 Spring WebFlux 相关依赖 导致的。org.springframework.web.reactive.function 包属于 Spring WebFlux 模块&#xff08;用于响应式 Web 开发&#xff09;&#xff0c;如…

Linux--线程池

目录 Linux线程池 线程池的概念 线程池的优点 线程池的应用场景 线程池的实现 Linux线程池 线程池的概念 线程池是一种线程的使用模式。 其存在的主要原因就为&#xff1a;线程过多会带来调度开销&#xff0c;进而影响缓存局部性和整体性能。而线程池维护着多个线程&#…

mars3d (基于 Cesium 的轻量化三维地图库)

mars3d 是什么? Mars3D 作为基于 Cesium 的轻量化框架,正以其简洁的 API 和强大的功能重新定义开发体验。它不仅解决了原生 Cesium 学习曲线陡峭的问题,还通过封装和优化实现了性能与易用性的双重突破。无论是智慧城市、低空经济还是军事仿真,Mars3D 都能提供高效的三维可视…

uniapp 中使用路由导航守卫,进行登录鉴权

前言: 在uniapp 使用中,对于登录界面可能需要路由守卫进行方便判断跳转,以下有两种方案,可以判断用户跳转的时候是否是登录状态 方案一: 1. 可以使用插件 hh-router-guard 2. 使用 uni-simpe-route 方案二: 使用通过uni提供的拦截器实现, uni.addInterceptor 1.新建in…

Leetcode 262. 行程和用户

1.题目基本信息 1.1.题目描述 表&#xff1a;Trips ----------------------- | Column Name | Type | ----------------------- | id | int | | client_id | int | | driver_id | int | | city_id | int | | status | enum | | request_at | varchar | -----------…

P1102 A-B 数对

P1102 A-B 数对 题目背景 出题是一件痛苦的事情! 相同的题目看多了也会有审美疲劳,于是我舍弃了大家所熟悉的 A+B Problem,改用 A-B 了哈哈! 题目描述 给出一串正整数数列以及一个正整数 C C C,要求计算出所有满足 A − B = C A - B = C A−B=C 的数对的个数(不同…

devextreme-vue的DxDataGrid如何显示行号列

devextreme-vue我使用的是23.2版本&#xff0c;其DxDataGrid如何显示行号列&#xff0c;官方一直没有方案。 DataGrid - How to display a row number in data rows in Angular | DevExpress Support dxDataGrid - provide capability to display a column with row numbers …