一、引言
????????在 C++ 編程的廣袤領域中,設計模式猶如閃耀的燈塔,為開發者指引著構建高效、可維護軟件系統的方向。設計模式并非神秘莫測的代碼魔法,實際上,我們在日常編程中或許早已與之打過交道。簡單來說,設計模式常常借助多態這一強大特性,達成各式各樣不同的操作方式。多態使得我們能夠以統一的接口來應對不同類型的對象,為設計模式的實現筑牢了根基。接下來,讓我們深入探索幾種常見的設計模式。
二、策略模式
(一)模式概述
????????策略模式包含一組策略類以及一個決策者類。其中,這組策略類是一系列繼承自同一個基類的類。策略類承擔著實現豐富多樣不同策略的職責,而決策者類則負責挑選合適的策略并予以執行。
(二)代碼實現
// 策略基類,定義了一個純虛函數 move,任何繼承自此類的子類都必須實現該函數
// 此基類為所有具體的移動策略提供了統一的接口
class MovementStrategy {
public:// 純虛函數,用于執行具體的移動操作virtual void move() = 0;// 虛析構函數,確保在通過基類指針刪除派生類對象時,能正確調用派生類的析構函數virtual ~MovementStrategy() {}
};// 步行策略類,繼承自 MovementStrategy 基類
// 該類實現了步行這種具體的移動策略
class WalkStrategy : public MovementStrategy {
public:// 重寫基類的 move 函數,實現步行操作的具體邏輯void move() override {std::cout << "Character is walking." << std::endl;}
};// 跑步策略類,繼承自 MovementStrategy 基類
// 該類實現了跑步這種具體的移動策略
class RunStrategy : public MovementStrategy {
public:// 重寫基類的 move 函數,實現跑步操作的具體邏輯void move() override {std::cout << "Character is running." << std::endl;}
};// 決策者類,負責選擇和執行具體的移動策略
class Character {
private:// 指向當前使用的移動策略對象的指針MovementStrategy* currentStrategy;
public:// 構造函數,初始化角色的移動策略Character(MovementStrategy* strategy) : currentStrategy(strategy) {}// 設置角色的移動策略void setStrategy(MovementStrategy* strategy) {currentStrategy = strategy;}// 調用當前移動策略的 move 函數,執行移動操作void move() {currentStrategy->move();}// 析構函數,釋放當前使用的移動策略對象所占用的內存~Character() {delete currentStrategy;}
};
(三)工作原理與實現邏輯
- 策略基類:
MovementStrategy
作為策略基類,定義了純虛函數move
。這就為所有具體的移動策略(如步行、跑步等)制定了統一的接口規范。任何繼承自該基類的子類都必須實現move
函數,以提供具體的策略實現。同時,虛析構函數確保在通過基類指針刪除派生類對象時,能夠正確調用派生類的析構函數,避免內存泄漏。 - 具體策略類:
WalkStrategy
和RunStrategy
分別繼承自MovementStrategy
基類。它們通過重寫move
函數,實現了各自獨特的移動策略。WalkStrategy
的move
函數輸出 “Character is walking.”,表示角色正在步行;RunStrategy
的move
函數輸出 “Character is running.”,表示角色正在跑步。 - 決策者類:
Character
類作為決策者類,持有一個指向MovementStrategy
對象的指針currentStrategy
。在構造函數中,通過傳入具體的策略對象來初始化currentStrategy
。setStrategy
函數用于動態更改角色當前使用的移動策略。move
函數則調用currentStrategy
所指向對象的move
函數,從而執行當前選定的移動策略。在析構函數中,釋放currentStrategy
所指向的對象,以確保內存的正確管理。
三、代理模式
(一)模式概述
????????代理模式僅需一組類,但這組類包含兩個具有不同功能的角色,即被代理者和代理者。
(二)代碼實現
// 被代理類(遠程數據庫訪問類)
// 該類負責實際從遠程數據庫獲取數據
class RemoteDatabase {
public:// 獲取遠程數據庫數據的函數std::string getData() {std::cout << "Accessing remote database..." << std::endl;return "Data from remote database";}
};// 代理類,用于代理對遠程數據庫的訪問
// 引入緩存機制,減少對遠程數據庫的頻繁訪問
class DatabaseProxy {
private:// 指向被代理的遠程數據庫對象的指針RemoteDatabase* realDatabase;// 緩存從遠程數據庫獲取的數據std::string cachedData;// 標記數據是否已緩存bool isCached;
public:// 構造函數,初始化被代理對象和緩存標記DatabaseProxy() : realDatabase(new RemoteDatabase), isCached(false) {}// 獲取數據的函數,優先從緩存中獲取,若緩存中沒有則從遠程數據庫獲取并緩存std::string getData() {if (isCached) {return cachedData;}cachedData = realDatabase->getData();isCached = true;return cachedData;}// 析構函數,釋放被代理對象所占用的內存~DatabaseProxy() {delete realDatabase;}
};
(三)工作原理與實現邏輯
- 被代理類:
RemoteDatabase
類代表被代理的遠程數據庫訪問對象。其getData
函數用于從遠程數據庫獲取數據,并在獲取過程中輸出 “Accessing remote database...”,表示正在訪問遠程數據庫,最后返回從數據庫獲取到的數據。 - 代理類:
DatabaseProxy
類作為代理者,內部持有一個指向RemoteDatabase
對象的指針realDatabase
,以及用于緩存數據的cachedData
和標記數據是否已緩存的isCached
。在構造函數中,創建RemoteDatabase
對象并初始化isCached
為false
。getData
函數是代理模式的核心邏輯所在,首先檢查isCached
是否為true
,若為true
,則直接返回緩存中的數據cachedData
,避免了再次訪問遠程數據庫;若為false
,則調用realDatabase
的getData
函數從遠程數據庫獲取數據,將獲取到的數據存入cachedData
并將isCached
設為true
,最后返回數據。在析構函數中,釋放realDatabase
所指向的對象,確保內存的正確釋放。
四、簡單工廠模式
(一)模式概述
????????簡單工廠模式下存在兩組類,一組是產品類,另一組是工廠類。產品類包含各種各樣不同的產品,每個產品能執行不同的任務。工廠類則依據提供的不同 “原材料”,生產出相應的產品。
(二)代碼實現
// 產品基類,定義了一個純虛函數 getResult,任何繼承自此類的子類都必須實現該函數
// 此基類為所有具體的計算產品提供了統一的接口
class Operation {
public:// 純虛函數,用于執行具體的計算操作并返回結果virtual int getResult(int num1, int num2) = 0;// 虛析構函數,確保在通過基類指針刪除派生類對象時,能正確調用派生類的析構函數virtual ~Operation() {}
};// 加法運算類,繼承自 Operation 基類
// 該類實現了加法計算這種具體的產品功能
class OperationAdd : public Operation {
public:// 重寫基類的 getResult 函數,實現加法計算的具體邏輯int getResult(int num1, int num2) override {return num1 + num2;}
};// 減法運算類,繼承自 Operation 基類
// 該類實現了減法計算這種具體的產品功能
class OperationSub : public Operation {
public:// 重寫基類的 getResult 函數,實現減法計算的具體邏輯int getResult(int num1, int num2) override {return num1 - num2;}
};// 工廠類,負責根據傳入的操作符生產相應的計算產品對象
class OperationFactory {
public:// 靜態工廠方法,根據傳入的操作符創建對應的計算產品對象static Operation* createOperation(const std::string& operate) {if (operate == "+") {return new OperationAdd;} else if (operate == "-") {return new OperationSub;}return nullptr;}
};
(三)工作原理與實現邏輯
- 產品基類:
Operation
作為產品基類,定義了純虛函數getResult
,用于執行具體的計算操作并返回結果。這為所有具體的計算產品(如加法、減法等)提供了統一的接口。任何繼承自該基類的子類都必須實現getResult
函數,以實現各自特定的計算功能。同時,虛析構函數確保在通過基類指針刪除派生類對象時,能夠正確調用派生類的析構函數,防止內存泄漏。 - 具體產品類:
OperationAdd
和OperationSub
分別繼承自Operation
基類。它們通過重寫getResult
函數,實現了各自的計算邏輯。OperationAdd
的getResult
函數將傳入的兩個數相加并返回結果,OperationSub
的getResult
函數則將兩個數相減并返回結果。 - 工廠類:
OperationFactory
類作為工廠類,提供了一個靜態的createOperation
方法。該方法接收一個表示操作符的字符串operate
作為參數,根據operate
的值判斷需要創建的產品類型。如果operate
為 “+”,則創建一個OperationAdd
對象并返回;如果operate
為 “-”,則創建一個OperationSub
對象并返回;若傳入的操作符不匹配任何已知的操作,則返回nullptr
。這種方式使得產品的創建邏輯集中在工廠類中,方便管理和維護。
(四)優缺點
- 優點:邏輯簡單直白,易于理解和實現。對于簡單的對象創建場景,使用簡單工廠模式可以快速搭建起系統的對象創建框架。
- 缺點:違反 “開閉原則”。當需要添加新的產品類(如乘法、除法運算類)時,必須修改工廠類的
createOperation
方法,添加新的條件判斷邏輯。這不僅增加了修改現有代碼的風險,還可能導致其他依賴該工廠類的代碼出現問題,不利于系統的維護和拓展。
五、工廠方法模式
(一)模式概述
????????工廠方法模式同樣包含一組產品類和一組工廠類。該模式旨在解決簡單工廠模式違反開閉原則的問題,它將每個產品都對應到一個獨立的工廠類去生產,即每個工廠只能生產一種產品。
(二)代碼實現
// 產品基類,定義了一個純虛函數 getResult,任何繼承自此類的子類都必須實現該函數
// 此基類為所有具體的計算產品提供了統一的接口
class Operation {
public:// 純虛函數,用于執行具體的計算操作并返回結果virtual int getResult(int num1, int num2) = 0;// 虛析構函數,確保在通過基類指針刪除派生類對象時,能正確調用派生類的析構函數virtual ~Operation() {}
};// 加法運算類,繼承自 Operation 基類
// 該類實現了加法計算這種具體的產品功能
class OperationAdd : public Operation {
public:// 重寫基類的 getResult 函數,實現加法計算的具體邏輯int getResult(int num1, int num2) override {return num1 + num2;}
};// 減法運算類,繼承自 Operation 基類
// 該類實現了減法計算這種具體的產品功能
class OperationSub : public Operation {
public:// 重寫基類的 getResult 函數,實現減法計算的具體邏輯int getResult(int num1, int num2) override {return num1 - num2;}
};// 加法工廠類,專門用于生產加法運算對象
class AddFactory {
public:// 靜態工廠方法,創建并返回一個加法運算對象static Operation* createOperation() {return new OperationAdd;}
};// 減法工廠類,專門用于生產減法運算對象
class SubFactory {
public:// 靜態工廠方法,創建并返回一個減法運算對象static Operation* createOperation() {return new OperationSub;}
};
(三)工作原理與實現邏輯
- 產品基類與具體產品類:這部分與簡單工廠模式類似,
Operation
作為產品基類定義了統一的接口getResult
,OperationAdd
和OperationSub
等具體產品類繼承自Operation
基類,并實現了各自的計算邏輯。 - 工廠類:在工廠方法模式中,每個產品都有對應的工廠類。
AddFactory
專門用于創建OperationAdd
對象,其createOperation
方法返回一個新的OperationAdd
實例;SubFactory
專門用于創建OperationSub
對象,其createOperation
方法返回一個新的OperationSub
實例。當需要添加新的產品類(如乘法運算類OperationMul
)時,只需創建對應的工廠類(如MulFactory
),并在其中實現創建OperationMul
對象的邏輯,而無需修改現有的工廠類代碼,從而遵循了開閉原則。
(四)優缺點
- 缺點:前期代碼量大,因為每一個產品都需要一個獨立工廠去生產,這無疑增加了代碼的編寫量和維護成本。例如,若有多種不同類型的計算產品,就需要創建同樣數量的工廠類。
- 優點:遵循了開閉原則,易于維護拓展。當系統需要添加新的產品時,只需創建新的產品類和對應的工廠類,而不會影響到現有的代碼。同時,獨立工廠生產能夠方便地進行定制化,比如可以在工廠類中添加特定的初始化邏輯或資源分配邏輯,以滿足不同產品的特殊需求。
六、抽象工廠模式
(一)模式概述
????????抽象工廠模式包含多組產品類和一組工廠類。工廠類能夠生產多個產品,并且不同的工廠生產的產品品牌不同。
(二)代碼實現
// 空調抽象類,定義了一個純虛函數 showInfo,任何繼承自此類的子類都必須實現該函數
// 此基類為所有具體品牌的空調產品提供了統一的接口
class AirConditioner {
public:// 純虛函數,用于展示空調的信息virtual void showInfo() = 0;// 虛析構函數,確保在通過基類指針刪除派生類對象時,能正確調用派生類的析構函數virtual ~AirConditioner() {}
};// 美的空調類,繼承自 AirConditioner 基類
// 該類實現了美的品牌空調的具體信息展示功能
class MideaAirConditioner : public AirConditioner {
public:// 重寫基類的 showInfo 函數,展示美的空調的信息void showInfo() override {std::cout << "This is Midea air conditioner." << std::endl;}
};// 格力空調類,繼承自 AirConditioner 基類
// 該類實現了格力品牌空調的具體信息展示功能
class GreeAirConditioner : public AirConditioner {
public:// 重寫基類的 showInfo 函數,展示格力空調的信息void showInfo() override {std::cout << "This is Gree air conditioner." << std::endl;}
};// 電冰箱抽象類,定義了一個純虛函數 showInfo,任何繼承自此類的子類都必須實現該函數
// 此基類為所有具體品牌的電冰箱產品提供了統一的接口
class Refrigerator {
public:// 純虛函數,用于展示電冰箱的信息virtual void showInfo() = 0;// 虛析構函數,確保在通過基類指針刪除派生類對象時,能正確調用派生類的析構函數virtual ~Refrigerator() {}
};// 美的電冰箱類,繼承自 Refrigerator 基類
// 該類實現了美的品牌電冰箱的具體信息展示功能
class MideaRefrigerator : public Refrigerator {
public:// 重寫基類的 showInfo 函數,展示美的電冰箱的信息void showInfo() override {std::cout << "This is Midea refrigerator." << std::endl;}
};// 格力電冰箱類,繼承自 Refrigerator 基類
// 該類實現了格力品牌電冰箱的具體信息展示功能
class GreeRefrigerator : public Refrigerator {
public:// 重寫基類的 showInfo 函數,展示格力電冰箱的信息void showInfo() override {std::cout << "This is Gree refrigerator." << std::endl;}