全是通俗易懂的講解,如果你本節之前的知識都掌握清楚,那就速速來看我的項目筆記吧~???
相關技術知識補充,也是最后的補充知識了~????????下文將加入項目代碼編寫!
目錄
設計模式
單例模式
餓漢模式?
懶漢模式
工廠模式
簡單工廠模式
工廠方法模式
抽象工廠模式
建造者模式
代理模式
設計模式
????????設計模式是前輩們對代碼開發經驗的總結,是解決特定問題的一系列套路。它不是語法規定,而是一套用來提高代碼可復用性、可維護性、可讀性、穩健性以及安全性的解決方案。
六大原則:
- 單一職責原則(Single Responsibility Principle)
- 原則內容:類的職責應該單一,一個方法只做一件事。職責劃分清晰,每次改動到最小單位的方法或類。
- 使用建議:兩個完全不一樣的功能不應該放一個類中,一個類中應該是一組相關性很高的函數、數據的封裝。
- 用例:網絡聊天:網絡通信 & 聊天,應該分割成為網絡通信類 & 聊天類。
- 開閉原則(Open Closed Principle)
- 原則內容:對擴展開放,對修改封閉。
- 使用建議:對軟件實體的改動,最好用擴展而非修改的方式。
- 用例:超時賣貨:商品價格 - 不是修改商品的原來價格,而是新增促銷價格。
- 里氏替換原則(Liskov Substitution Principle)
- 原則內容:通俗點講,就是只要父類能出現的地方,子類就可以出現,而且替換為子類也不會產生任何錯誤或異常。在繼承類時,務必重寫父類中所有的方法,尤其需要注意父類的 protected 方法,子類盡量不要暴露自己的 public 方法供外界調用 。
- 使用建議:子類必須完全實現父類的方法,子類可以有自己的個性。覆蓋或實現父類的方法時,輸入參數可以被放大,輸出可以縮小。
- 用例:跑步運動員類 - 會跑步,子類長跑運動員 - 會跑步且擅長長跑,子類短跑運動員 - 會跑步且擅長短跑。
- 依賴倒置原則(Dependence Inversion Principle)
- 原則內容:高層模塊不應該依賴低層模塊,兩者都應該依賴其抽象,不可分割的原子邏輯就是低層模式,原子邏輯組裝成的就是高層模塊。模塊間依賴通過抽象(接口)發生,具體類之間不直接依賴。
- 使用建議:每個類都盡量有抽象類,任何類都不應該從具體類派生。盡量不要重寫基類的方法。結合里氏替換原則使用。
- 用例:奔馳車司機類 - 只能開奔馳; 司機類 - 給什么車,就開什么車; 開車的人:司機 - 依賴于抽象。
- 迪米特法則(Law of Demeter),又叫 “最少知道法則”
- 原則內容:盡量減少對象之間的交互,從而減小類之間的耦合。一個對象應該對其他對象有最少的了解。對類的低耦合提出了明確的要求:只和直接的朋友交流,朋友之間也是有距離的。自己的就是自己的(如果一個方法放在本類中,既不增加類間關系,也對本類不產生負面影響,那就放置在本類中 )。
- 使用建議:無特殊額外建議。
- 用例:老師讓班長點名 - 老師給班長一個名單,班長完成點名勾選,返回結果,而不是班長點名,老師勾選。
- 接口隔離原則(Interface Segregation Principle)
- 原則內容:客戶端不應該依賴它不需要的接口,類間的依賴關系應該建立在最小的接口上。
- 使用建議:接口設計盡量精簡單一,但是不要對外暴露沒有實際意義的接口。
- 用例:修改密碼,不應該提供修改用戶信息接口,而就是單一的最小修改密碼接口,更不要暴露數據庫操作。
????????從整體上來理解六大設計原則,可以簡要的概括為一句話,用抽象構建框架,用實現擴展細節,具體到每一條設計原則,則對應一條注意事項:
- 單一職責原則告訴我們實現類要職責單一;
- 里氏替換原則告訴我們不要破壞繼承體系;
- 依賴倒置原則告訴我們要面向接口編程;
- 接口隔離原則告訴我們在設計接口的時候要精簡單一;
- 迪米特法則告訴我們要降低耦合;
- 開閉原則是總綱,告訴我們要對擴展開放,對修改關閉。
? 我們了解設計模式之后,我們來了解具體的設計模式吧
單例模式
單例模式的定義:“一個類只能創建一個對象,即單例模式。該設計模式可以保證系統中該類只有一個實例,并提供一個訪問它的全局訪問點,該實例被所有程序模塊共享”。這表明單例模式是一種特殊的設計模式,在這種模式下,一個類在整個程序運行過程中只能有一個對象(實例)存在。并且有一個固定的、全局都能訪問到的方式去獲取這個唯一的實例,同時這個實例會被程序里的各個模塊所使用。
舉例說明:“在某個服務器程序中,該服務器的配置信息存放在一個文件中,這些配置數據由一個單例對象統一讀取,然后服務進程中的其他對象再通過這個單例對象獲取這些配置信息,這種方式簡化了在復雜環境下的配置管理” 。
- 在這個服務器程序的場景里,服務器的配置信息都在一個文件中。
- 我們創建一個單例對象,這個單例對象的職責就是去讀取這個配置文件里的信息。由于它是單例的,整個程序中只有這么一個對象能做這件事,保證了配置信息讀取的唯一性和一致性。
- 而服務進程中的其他對象,如果它們需要用到這些配置信息,不需要各自去讀取文件(這樣可能會導致重復讀取或者讀取不一致等問題),只需要通過訪問這個單例對象,就能獲取到配置信息。
- 這樣做的好處就是,在比較復雜的服務器程序環境中,對配置信息的管理變得更加簡單和高效。因為所有關于配置信息的操作都圍繞著這一個單例對象進行,避免了多個對象同時操作配置信息可能帶來的混亂。
????????例如,想象有多個模塊都需要讀取數據庫的連接配置信息。如果沒有單例模式,每個模塊可能都要去讀取配置文件,可能會出現讀取錯誤、配置不一致等問題。而使用單例模式,有一個專門的單例對象讀取配置文件中的數據庫連接信息,其他模塊都從這個單例對象獲取信息,就能保證整個系統使用的數據庫連接配置是一致的,也便于對配置進行修改和維護。
單例模式有兩種實現模式:餓漢模式和懶漢模式。
餓漢模式?
在 C++ 里,餓漢模式是單例模式的一種實現方式。單例模式的目的是保證一個類僅有一個實例,并提供一個全局訪問點來獲取該實例。
餓漢模式的特點
- 實例創建時機:在程序開始運行時就創建單例類的實例,而不是在首次使用時才創建。“餓漢” 就像一個饑餓的人,迫不及待地創建實例。
- 線程安全:由于實例在程序啟動時就已經創建好,所以不存在多線程環境下同時創建多個實例的問題,天生具備線程安全性。
示例代碼
下面是一個簡單的餓漢模式實現示例:
#include <iostream>class Singleton {
private:// 構造函數私有化,防止外部創建對象Singleton() {}// 拷貝構造函數私有化,防止拷貝Singleton(const Singleton&) = delete;// 賦值運算符私有化,防止賦值Singleton& operator=(const Singleton&) = delete;// 靜態成員變量,存儲單例實例static Singleton instance;public:// 靜態成員函數,用于獲取單例實例static Singleton& getInstance() {return instance;}void doSomething() {std::cout << "Singleton is doing something." << std::endl;}
};// 初始化靜態成員變量
Singleton Singleton::instance;int main() {// 獲取單例實例Singleton& singleton = Singleton::getInstance();// 調用實例的方法singleton.doSomething();return 0;
}
代碼解釋
- 構造函數私有化:
Singleton
?類的構造函數被聲明為私有,這樣外部代碼就無法直接創建?Singleton
?類的對象。- 靜態成員變量:
static Singleton instance;
?是一個靜態成員變量,用于存儲單例實例。在類外進行了初始化?Singleton Singleton::instance;
,這確保了在程序啟動時就創建了實例。- 靜態成員函數:
static Singleton& getInstance()
?是一個靜態成員函數,用于獲取單例實例。由于它是靜態的,可以直接通過類名調用。- 拷貝構造函數和賦值運算符刪除:為了防止通過拷貝或賦值操作創建新的實例,將拷貝構造函數和賦值運算符聲明為?
delete
。
使用步驟
- 定義單例類:按照上述示例,將構造函數、拷貝構造函數和賦值運算符私有化,并定義一個靜態成員變量和一個靜態成員函數。
- 初始化靜態成員變量:在類外對靜態成員變量進行初始化。
- 獲取單例實例:通過調用靜態成員函數?
getInstance()
?來獲取單例實例,并調用實例的方法。
????????餓漢模式的優點是實現簡單且線程安全,但缺點是如果單例實例占用資源較多,而程序可能并不需要使用該實例,會造成資源浪費。
懶漢模式
在 C++ 中,懶漢模式同樣是單例模式的一種實現方式。單例模式的核心是確保一個類僅有一個實例,并提供一個全局訪問點來獲取該實例。
懶漢模式的特點
- 實例創建時機:懶漢模式與餓漢模式不同,它是在首次使用單例實例時才進行創建。就像一個 “懶人”,不到萬不得已不會去創建實例。
- 線程安全問題:在多線程環境下,如果不進行特殊處理,可能會出現多個線程同時判斷實例未創建,從而各自創建一個實例的情況,導致單例模式失效。所以,在多線程環境中使用懶漢模式需要考慮線程安全問題。
簡單懶漢模式(非線程安全)
以下是一個簡單的非線程安全的懶漢模式實現示例:
#include <iostream>class Singleton {
private:// 構造函數私有化,防止外部創建對象Singleton() {}// 拷貝構造函數私有化,防止拷貝Singleton(const Singleton&) = delete;// 賦值運算符私有化,防止賦值Singleton& operator=(const Singleton&) = delete;// 靜態成員指針,用于存儲單例實例static Singleton* instance;public:// 靜態成員函數,用于獲取單例實例static Singleton* getInstance() {if (instance == nullptr) {instance = new Singleton();}return instance;}void doSomething() {std::cout << "Singleton is doing something." << std::endl;}
};// 初始化靜態成員指針
Singleton* Singleton::instance = nullptr;int main() {// 獲取單例實例Singleton* singleton = Singleton::getInstance();// 調用實例的方法singleton->doSomething();return 0;
}
代碼解釋
- 構造函數私有化:
Singleton
?類的構造函數被聲明為私有,這樣外部代碼就無法直接創建?Singleton
?類的對象。- 靜態成員指針:
static Singleton* instance;
?是一個靜態成員指針,用于存儲單例實例。初始化為?nullptr
,表示還未創建實例。- 靜態成員函數:
static Singleton* getInstance()
?是一個靜態成員函數,用于獲取單例實例。在函數內部,首先檢查?instance
?是否為?nullptr
,如果是,則創建一個新的?Singleton
?實例;否則,直接返回已有的實例。- 拷貝構造函數和賦值運算符刪除:為了防止通過拷貝或賦值操作創建新的實例,將拷貝構造函數和賦值運算符聲明為?
delete
。
線程安全的懶漢模式(雙重檢查鎖定)
在多線程環境中,可以使用雙重檢查鎖定(Double-Checked Locking)來實現線程安全的懶漢模式:
#include <iostream>
#include <mutex>class Singleton {
private:// 構造函數私有化,防止外部創建對象Singleton() {}// 拷貝構造函數私有化,防止拷貝Singleton(const Singleton&) = delete;// 賦值運算符私有化,防止賦值Singleton& operator=(const Singleton&) = delete;// 靜態成員指針,用于存儲單例實例static Singleton* instance;// 靜態互斥鎖,用于線程同步static std::mutex mtx;public:// 靜態成員函數,用于獲取單例實例static Singleton* getInstance() {if (instance == nullptr) {std::lock_guard<std::mutex> lock(mtx);if (instance == nullptr) {instance = new Singleton();}}return instance;}void doSomething() {std::cout << "Singleton is doing something." << std::endl;}
};// 初始化靜態成員指針
Singleton* Singleton::instance = nullptr;
// 初始化靜態互斥鎖
std::mutex Singleton::mtx;int main() {// 獲取單例實例Singleton* singleton = Singleton::getInstance();// 調用實例的方法singleton->doSomething();return 0;
}
代碼解釋
- 雙重檢查:在?
getInstance()
?函數中,首先進行一次非鎖定檢查,判斷?instance
?是否為?nullptr
。如果不為?nullptr
,則直接返回實例,避免了不必要的鎖競爭。如果為?nullptr
,則加鎖進行第二次檢查,確保在加鎖期間沒有其他線程已經創建了實例。- 互斥鎖:使用?
std::mutex
?來實現線程同步,確保在同一時間只有一個線程可以進入臨界區創建實例。
使用步驟
- 定義單例類:按照上述示例,將構造函數、拷貝構造函數和賦值運算符私有化,并定義一個靜態成員指針和一個靜態成員函數。
- 初始化靜態成員指針:在類外對靜態成員指針進行初始化,初始值為?
nullptr
。- 獲取單例實例:通過調用靜態成員函數?
getInstance()
?來獲取單例實例,并調用實例的方法。
????????懶漢模式的優點是在需要時才創建實例,避免了不必要的資源浪費;缺點是實現相對復雜,特別是在多線程環境中需要考慮線程安全問題。
工廠模式
????????工廠模式是一種創建型設計模式,它提供了一種創建對象的最佳方式。在工廠模式中,我們創建對象時不會對上層暴露創建邏輯,而是通過使用一個共同結構來指向新創建的對象,以此實現創建 - 使用的分離。
工廠模式可以分為:
簡單工廠模式
- 簡單工廠模式:簡單工廠模式實現由一個工廠對象通過類型決定創建出來指定產品類的實例。假設有個工廠能生產出水果,當客戶需要產品的時候明確告知工廠生產哪類水果,工廠需要接收用戶提供的類別信息,當新增產品的時候,工廠內部去添加新產品的生產方式。
簡單工廠模式代碼示例
// 簡單工廠模式: 通過參數控制可以生產任何產品
// 優點: 簡單粗暴,直觀易懂。使用一個工廠生產同一等級結構下的任意產品
// 缺點:
// 1. 所有東西生產在一起,產品太多會導致代碼量龐大
// 2. 開閉原則遵循(開放拓展,關閉修改)的不是太好,要新增產品就必須修改工廠方法。#include <iostream>
#include <string>
#include <memory>class Fruit {
public:Fruit() {}virtual void show() = 0;
};class Apple : public Fruit {
public:Apple() {}virtual void show() {std::cout << "我是一個蘋果" << std::endl;}
};class Banana : public Fruit {
public:Banana() {}virtual void show() {std::cout << "我是一個香蕉" << std::endl;}
};class FruitFactory {
public:static std::shared_ptr<Fruit> create(const std::string &name) {if (name == "蘋果") {return std::make_shared<Apple>();} else if (name == "香蕉") {return std::make_shared<Banana>();}return std::shared_ptr<Fruit>();}
};int main() {std::shared_ptr<Fruit> fruit = FruitFactory::create("蘋果");fruit->show();fruit = FruitFactory::create("香蕉");fruit->show();return 0;
}
????????這個模式的結構和管理產品對象的方式十分簡單,但是它的擴展性非常差,當我們需要新增產品的時候,就需要去修改工廠類新增一個類型的產品創建邏輯,違背了開閉原則。
工廠方法模式
工廠方法模式是在簡單工廠模式基礎上的擴展,在該模式下新增多個工廠,每個產品對應一個工廠。例如有 A、B 兩種產品,就分別開設工廠 A 負責生產產品 A ,工廠 B 負責生產產品 B 。用戶只需知道產品對應的工廠名,無需了解具體產品信息,工廠也只需專注生產,無需接收客戶對產品類別的指定。
代碼示例及注釋
#include <iostream>
#include <string>
#include <memory>// 水果基類,定義了抽象方法show(),后續具體水果類需實現該方法,用于展示水果相關信息
class Fruit {
public:Fruit() {}virtual void show() = 0;
};// 蘋果類,繼承自Fruit基類,實現了show()方法,用于輸出蘋果相關信息
class Apple : public Fruit {
public:Apple() {}virtual void show() {std::cout << "我是一個蘋果" << std::endl;}
private:std::string _color; // 私有成員變量,可用于表示蘋果顏色等信息
};// 香蕉類,繼承自Fruit基類,實現了show()方法,用于輸出香蕉相關信息
class Banana : public Fruit {
public:Banana() {}virtual void show() {std::cout << "我是一個香蕉" << std::endl;}
private:std::string _color; // 私有成員變量,可用于表示香蕉顏色等信息
};// 水果工廠抽象基類,定義了抽象的create()方法,用于創建水果對象,具體實現由子類完成
class FruitFactory {
public:virtual std::shared_ptr<Fruit> create() = 0;
};// 蘋果工廠類,繼承自FruitFactory,重寫create()方法,用于創建蘋果對象
class AppleFactory : public FruitFactory {
public:virtual std::shared_ptr<Fruit> create() {return std::make_shared<Apple>(); // 創建并返回一個蘋果對象的智能指針}
};// 香蕉工廠類,繼承自FruitFactory,重寫create()方法,用于創建香蕉對象
class BananaFactory : public FruitFactory {
public:virtual std::shared_ptr<Fruit> create() {return std::make_shared<Banana>(); // 創建并返回一個香蕉對象的智能指針}
};int main() {// 創建一個指向AppleFactory對象的智能指針,這里使用AppleFactory來生產蘋果std::shared_ptr<FruitFactory> factory(new AppleFactory());// 通過蘋果工廠創建一個水果對象(實際是蘋果對象)std::shared_ptr<Fruit> fruit = factory->create();// 調用蘋果對象的show()方法,輸出"我是一個蘋果"fruit->show();// 重置factory指針,使其指向BananaFactory對象,準備生產香蕉factory.reset(new BananaFactory());// 通過香蕉工廠創建一個水果對象(實際是香蕉對象)fruit = factory->create();// 調用香蕉對象的show()方法,輸出"我是一個香蕉"fruit->show();return 0;
}
模式優缺點
- 優點:
- 減輕了工廠類的負擔,將某類產品的生產交給指定的工廠來進行 。
- 開閉原則遵循較好,添加新產品只需要新增產品的工廠即可,不需要修改原先的工廠類 。
- 缺點:對于某種可以形成一組產品族的情況處理較為復雜,需要創建大量的工廠類。每次增加一個產品時,都需要增加一個具體產品類和工廠類,這會使得系統中類的個數成倍增加,在一定程度上增加了系統的耦合度。
抽象工廠模式
????????抽象工廠模式是在工廠方法模式基礎上的進一步拓展。工廠方法模式雖引入工廠等級結構,解決了簡單工廠模式中工廠類職責過重問題,但每個工廠只生產一類產品,可能導致系統中工廠類數量龐大,開銷增加。抽象工廠模式的基本思想是把一些相關產品組成一個產品族(即位于不同產品等級結構中功能相關聯的產品集合 ),由同一個工廠來統一生產。
代碼示例及注釋
#include <iostream>
#include <string>
#include <memory>// 水果基類,定義抽象方法show(),用于展示水果相關信息,具體由子類實現
class Fruit {
public:Fruit() {}virtual void show() = 0;
};// 蘋果類,繼承自Fruit基類,實現show()方法,用于輸出蘋果相關信息
class Apple : public Fruit {
public:Apple() {}virtual void show() {std::cout << "我是一個蘋果" << std::endl;}
private:std::string _color; // 私有成員變量,可用于表示蘋果顏色等信息
};// 香蕉類,繼承自Fruit基類,實現show()方法,用于輸出香蕉相關信息
class Banana : public Fruit {
public:Banana() {}virtual void show() {std::cout << "我是一個香蕉" << std::endl;}
private:std::string _color; // 私有成員變量,可用于表示香蕉顏色等信息
};// 動物基類,定義抽象方法voice(),用于發出動物叫聲,具體由子類實現
class Animal {
public:virtual void voice() = 0;
};// 羊類,繼承自Animal基類,實現voice()方法,輸出羊的叫聲
class Lamb : public Animal {
public:void voice() {std::cout << "咩咩咩\n";}
};// 狗類,繼承自Animal基類,實現voice()方法,輸出狗的叫聲
class Dog : public Animal {
public:void voice() {std::cout << "汪汪汪\n";}
};// 工廠抽象基類,定義了創建水果和動物對象的抽象方法,具體實現由子類完成
class Factory {
public:virtual std::shared_ptr<Fruit> getFruit(const std::string &name) = 0;virtual std::shared_ptr<Animal> getAnimal(const std::string &name) = 0;
};// 水果工廠類,繼承自Factory,實現創建水果對象的方法
class FruitFactory : public Factory {
public:// 該方法在當前類中不創建動物對象,直接返回空指針virtual std::shared_ptr<Animal> getAnimal(const std::string &name) {return std::shared_ptr<Animal>();}virtual std::shared_ptr<Fruit> getFruit(const std::string &name) {if (name == "蘋果") {return std::make_shared<Apple>(); // 創建并返回一個蘋果對象的智能指針} else if (name == "香蕉") {return std::make_shared<Banana>(); // 創建并返回一個香蕉對象的智能指針}return std::shared_ptr<Fruit>(); // 若名稱不匹配,返回空的智能指針}
};// 動物工廠類,繼承自Factory,實現創建動物對象的方法
class AnimalFactory : public Factory {
public:// 該方法在當前類中不創建水果對象,直接返回空指針virtual std::shared_ptr<Fruit> getFruit(const std::string &name) {return std::shared_ptr<Fruit>();}virtual std::shared_ptr<Animal> getAnimal(const std::string &name) {if (name == "小羊") {return std::make_shared<Lamb>(); // 創建并返回一個羊對象的智能指針} else if (name == "小狗") {return std::make_shared<Dog>(); // 創建并返回一個狗對象的智能指針}return std::shared_ptr<Animal>(); // 若名稱不匹配,返回空的智能指針}
};// 工廠生產者類,用于根據傳入的名稱獲取對應的工廠對象
class FactoryProducer {
public:static std::shared_ptr<Factory> getFactory(const std::string &name) {if (name == "動物") {return std::make_shared<AnimalFactory>(); // 返回動物工廠對象的智能指針} else {return std::make_shared<FruitFactory>(); // 返回水果工廠對象的智能指針}}
};int main() {// 獲取水果工廠對象std::shared_ptr<Factory> fruit_factory = FactoryProducer::getFactory("水果");// 通過水果工廠創建蘋果對象并調用其show()方法std::shared_ptr<Fruit> fruit = fruit_factory->getFruit("蘋果");fruit->show();// 通過水果工廠創建香蕉對象并調用其show()方法fruit = fruit_factory->getFruit("香蕉");fruit->show();// 獲取動物工廠對象std::shared_ptr<Factory> animal_factory = FactoryProducer::getFactory("動物");// 通過動物工廠創建羊對象并調用其voice()方法std::shared_ptr<Animal> animal = animal_factory->getAnimal("小羊");animal->voice();// 通過動物工廠創建狗對象并調用其voice()方法animal = animal_factory->getAnimal("小狗");animal->voice();return 0;
}
模式優缺點
- 優點:
- 可以將一組相關的產品對象的創建封裝在一起,提高了代碼的內聚性和可維護性 。
- 當需要創建多個相關產品時,減少了創建對象的復雜程度 。
- 缺點:
- 增加新的產品等級結構復雜,若要添加新的產品族,需要對抽象層代碼進行較大修改,違背了 “開閉原則” 。
建造者模式
????????建造者模式是一種創建型設計模式,它利用多個簡單對象逐步構建出一個復雜對象,能夠將復雜對象的構建過程和其表示形式相分離,為創建對象提供了一種優化方式,主要用于應對對象構建過程過于繁雜的情況。
建造者模式的四個核心類
- 抽象產品類:定義了產品的抽象屬性和行為。
- 具體產品類:是具體的產品對象類,繼承自抽象產品類,實現了具體的產品功能。
- 抽象 Builder 類:為創建產品對象所需的各個部件定義了抽象接口。
- 具體產品的 Builder 類:實現抽象 Builder 類的接口,負責具體構建各個部件。
- 指揮者 Director 類:統一管理組裝過程,提供給調用者使用,通過指揮者來構建完整的產品。
???????下面通過一個簡單的電腦組裝示例,使用 C++ 代碼來解釋建造者模式。在這個示例中,我們要構建不同配置的電腦,包括主板和顯示器等組件。
#include <iostream>
#include <memory>/*抽象電腦類*/
class Computer {public:using ptr = std::shared_ptr<Computer>;Computer() {}void setBoard(const std::string &board) {_board = board;}void setDisplay(const std::string &display) {_display = display;}virtual void setOs() = 0;std::string toString() {std::string computer = "Computer:{\n";computer += "\tboard=" + _board + ",\n"; computer += "\tdisplay=" + _display + ",\n"; computer += "\tOs=" + _os + ",\n"; computer += "}\n";return computer;}protected:std::string _board;std::string _display;std::string _os;
};/*具體產品類*/
class MacBook : public Computer {public:using ptr = std::shared_ptr<MacBook>;MacBook() {}virtual void setOs() {_os = "Max Os X12";}
};/*抽象建造者類:包含創建一個產品對象的各個部件的抽象接口*/
class Builder {public:using ptr = std::shared_ptr<Builder>;virtual void buildBoard(const std::string &board) = 0;virtual void buildDisplay(const std::string &display) = 0;virtual void buildOs() = 0;virtual Computer::ptr build() = 0;
};/*具體產品的具體建造者類:實現抽象接口,構建和組裝各個部件*/
class MackBookBuilder : public Builder {public:using ptr = std::shared_ptr<MackBookBuilder>;MackBookBuilder(): _computer(new MacBook()) {}virtual void buildBoard(const std::string &board) {_computer->setBoard(board);}virtual void buildDisplay(const std::string &display) {_computer->setDisplay(display);}virtual void buildOs() {_computer->setOs();}virtual Computer::ptr build() {return _computer;}private:Computer::ptr _computer;
};/*指揮者類,提供給調用者使用,通過指揮者來獲取產品*/
class Director {public:Director(Builder* builder):_builder(builder){}void construct(const std::string &board, const std::string &display) {_builder->buildBoard(board);_builder->buildDisplay(display);_builder->buildOs();}private:Builder::ptr _builder;
};int main()
{Builder *buidler = new MackBookBuilder();std::unique_ptr<Director> pd(new Director(buidler));pd->construct("英特爾主板", "VOC顯示器");Computer::ptr computer = buidler->build();std::cout << computer->toString();return 0;
}
?代碼解釋
抽象產品類?
Computer
:
- 定義了電腦的基本屬性,包括主板(
_board
)、顯示器(_display
)和操作系統(_os
)。- 提供了設置主板和顯示器的方法?
setBoard
?和?setDisplay
。- 包含一個純虛函數?
setOs
,這使得?Computer
?成為抽象類,具體的電腦產品類需要實現該方法來設置操作系統。toString
?方法用于將電腦的配置信息格式化為字符串并返回,方便輸出展示。具體產品類?
MacBook
:
- 繼承自?
Computer
?類,實現了?setOs
?方法,將操作系統設置為?"Max Os X12"
。抽象建造者類?
Builder
:
- 定義了創建電腦各個部件的抽象接口,包括?
buildBoard
(構建主板)、buildDisplay
(構建顯示器)、buildOs
(構建操作系統)以及?build
(獲取構建好的電腦對象)。具體產品的具體建造者類?
MackBookBuilder
:
- 繼承自?
Builder
?類,在構造函數中創建了一個?MacBook
?對象。- 實現了?
buildBoard
、buildDisplay
?和?buildOs
?方法,分別調用?MacBook
?對象的相應設置方法來構建電腦的各個部件。build
?方法返回構建好的?MacBook
?對象。指揮者類?
Director
:
- 接收一個?
Builder
?對象,通過?construct
?方法調用?Builder
?對象的構建方法,完成電腦的組裝過程。
main
?函數:
- 創建了一個?
MackBookBuilder
?對象。- 創建?
Director
?對象并傳入?MackBookBuilder
?對象。- 調用?
Director
?的?construct
?方法,傳入主板和顯示器的信息,完成電腦的構建。- 調用?
MackBookBuilder
?的?build
?方法獲取構建好的電腦對象。- 輸出電腦的配置信息。
????????通過這種方式,建造者模式將電腦的構建過程和表示分離,使得我們可以方便地構建不同配置的電腦,同時也提高了代碼的可維護性和可擴展性。
代理模式
?
????????代理模式指代理控制對其他對象的訪問,也就是代理對象控制對原對象的引用。在某些情況下,一個對象不適合或者不能直接被引用訪問,而代理對象可以在客戶端和目標對象之間起到中介的作用。
????????代理模式的結構包括一個是真正的你要訪問的對象 (目標類)、一個是代理對象。目標對象與代理對象實現同一個接口,先訪問代理類再通過代理類訪問目標對象。代理模式分為靜態代理、動態代理:
- 靜態代理指的是,在編譯時就已經確定好了代理類和被代理類的關系。也就是說,在編譯時就已經確定了代理類要代理的是哪個被代理類。
- 動態代理指的是,在運行時才動態生成代理類,并將其與被代理類綁定。這意味著,在運行時才能確定代理類要代理的是哪個被代理類。
????????以租房為例,房東將房子租出去,但是要租房子出去,需要發布招租啟示,帶人看房,負責維修,這些工作中有些操作并非房東能完成,因此房東為了圖省事,將房子委托給中介進行租賃。代理模式實現:
// 以房東通過中介租房子為例理解代理模式
#include <iostream>
#include <string>// 抽象接口類,定義租房的抽象行為
class RentHouse {
public:// 純虛函數,用于定義租房的行為,具體實現由子類完成virtual void rentHouse() = 0;
};// 房東類,繼承自RentHouse接口,代表真實的目標對象
class Landlord : public RentHouse {
public:// 實現RentHouse接口中的rentHouse方法,描述房東將房子租出去的行為void rentHouse() {std::cout << "將房子租出去\n"; }
};// 中介類,繼承自RentHouse接口,作為代理對象
class Intermediary : public RentHouse {
public:// 實現RentHouse接口中的rentHouse方法void rentHouse() {// 中介在代理租房前可以添加一些額外操作,比如發布招租信息等std::cout << "中介發布招租信息\n"; // 調用房東實際的租房操作_landlord.rentHouse(); // 中介在代理租房后可以添加一些額外操作,比如安排后續事宜等std::cout << "中介安排后續事宜\n"; }
private:// 持有房東對象,用于在代理行為中調用房東的實際租房操作Landlord _landlord;
};int main() {Intermediary intermediary;intermediary.rentHouse();return 0;
}
?如果你對日志系統感到興趣,歡迎關注我👉【A charmer】
后續我將繼續帶你實現日志系統~