設計模式(七)

迭代器模式(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
英文地址,請注明出處:http://en.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 …