文章目錄
- 一、創建型模式
- 1. 單例模式
- 2. 工廠模式
- 二、結構型模式
- 1. 裝飾器模式
- 2. 代理模式
- 三、行為型模式
- 1. 觀察者模式
- 2. 策略模式
一、創建型模式
1. 單例模式
C++八股 —— 單例模式_c++ 單例模式-CSDN博客
2. 工廠模式
參考:【設計模式】工廠模式詳解-----簡單工廠模式、工廠方法模式、抽象工廠模式-CSDN博客
什么是工廠模式
工廠模式是一種創建型設計模式,它提供了一種創建對象的最佳方式,而無需暴露對象創建的邏輯細節。
工廠模式的三種類型
- 簡單工廠模式:一個工廠類根據傳入的參數決定創建哪種產品類的實例
- 工廠方法模式:定義一個創建對象的接口,但讓子類決定實例化哪個類
- 抽象工廠模式:提供一個創建一系列相關或相互依賴對象的接口,而無需指定它們具體的類
工廠模式的優點
- 封裝創建邏輯:將對象的創建與使用分離
- 代碼解耦:客戶端代碼不需要知道具體產品類的類名
- 易于擴展:添加新產品時,只需擴展工廠類,符合開閉原則
- 統一管理:可以對對象的創建進行統一的管理和控制
適用場景
- 當一個類不知道它所必須創建的對象的類時
- 當一個類希望由其子類來指定它所創建的對象時
- 當類將創建對象的職責委托給多個幫助子類中的某一個,并且你希望將哪一個幫助子類是代理者這一信息局部化時
簡單工程模式示例
#include <iostream>
#include <string>
#include <memory>// 產品接口
class Shape {
public:virtual void draw() = 0;virtual ~Shape() {}
};// 具體產品類
class Circle : public Shape {
public:void draw() override {std::cout << "Drawing a Circle" << std::endl;}
};class Rectangle : public Shape {
public:void draw() override {std::cout << "Drawing a Rectangle" << std::endl;}
};class Triangle : public Shape {
public:void draw() override {std::cout << "Drawing a Triangle" << std::endl;}
};// 簡單工廠
class ShapeFactory {
public:static std::unique_ptr<Shape> createShape(const std::string& shapeType) {if (shapeType == "CIRCLE") {return std::make_unique<Circle>();} else if (shapeType == "RECTANGLE") {return std::make_unique<Rectangle>();} else if (shapeType == "TRIANGLE") {return std::make_unique<Triangle>();}return nullptr;}
};int main() {// 使用工廠創建對象auto circle = ShapeFactory::createShape("CIRCLE");auto rectangle = ShapeFactory::createShape("RECTANGLE");auto triangle = ShapeFactory::createShape("TRIANGLE");circle->draw();rectangle->draw();triangle->draw();return 0;
}
工廠方法模式
#include <iostream>
#include <memory>// 產品接口
class Button {
public:virtual void render() = 0;virtual void onClick() = 0;virtual ~Button() {}
};// 具體產品
class WindowsButton : public Button {
public:void render() override {std::cout << "Rendering a Windows button" << std::endl;}void onClick() override {std::cout << "Windows button clicked" << std::endl;}
};class WebButton : public Button {
public:void render() override {std::cout << "Rendering a Web button" << std::endl;}void onClick() override {std::cout << "Web button clicked" << std::endl;}
};// 創建者類
class Dialog {
public:virtual std::unique_ptr<Button> createButton() = 0;void render() {auto button = createButton();button->render();button->onClick();}virtual ~Dialog() {}
};// 具體創建者
class WindowsDialog : public Dialog {
public:std::unique_ptr<Button> createButton() override {return std::make_unique<WindowsButton>();}
};class WebDialog : public Dialog {
public:std::unique_ptr<Button> createButton() override {return std::make_unique<WebButton>();}
};int main() {std::unique_ptr<Dialog> dialog;// 根據配置或環境選擇創建者std::string config = "Windows"; // 可以改為 "Web" 來測試if (config == "Windows") {dialog = std::make_unique<WindowsDialog>();} else if (config == "Web") {dialog = std::make_unique<WebDialog>();}if (dialog) {dialog->render();}return 0;
}
抽象工程模式
#include <iostream>
#include <memory>// 抽象產品A
class Checkbox {
public:virtual void paint() = 0;virtual ~Checkbox() {}
};// 具體產品A1
class WindowsCheckbox : public Checkbox {
public:void paint() override {std::cout << "Rendering a Windows checkbox" << std::endl;}
};// 具體產品A2
class WebCheckbox : public Checkbox {
public:void paint() override {std::cout << "Rendering a Web checkbox" << std::endl;}
};// 抽象產品B
class Button {
public:virtual void paint() = 0;virtual ~Button() {}
};// 具體產品B1
class WindowsButton : public Button {
public:void paint() override {std::cout << "Rendering a Windows button" << std::endl;}
};// 具體產品B2
class WebButton : public Button {
public:void paint() override {std::cout << "Rendering a Web button" << std::endl;}
};// 抽象工廠
class GUIFactory {
public:virtual std::unique_ptr<Button> createButton() = 0;virtual std::unique_ptr<Checkbox> createCheckbox() = 0;virtual ~GUIFactory() {}
};// 具體工廠1
class WindowsFactory : public GUIFactory {
public:std::unique_ptr<Button> createButton() override {return std::make_unique<WindowsButton>();}std::unique_ptr<Checkbox> createCheckbox() override {return std::make_unique<WindowsCheckbox>();}
};// 具體工廠2
class WebFactory : public GUIFactory {
public:std::unique_ptr<Button> createButton() override {return std::make_unique<WebButton>();}std::unique_ptr<Checkbox> createCheckbox() override {return std::make_unique<WebCheckbox>();}
};// 客戶端代碼
class Application {
private:std::unique_ptr<GUIFactory> factory;std::unique_ptr<Button> button;std::unique_ptr<Checkbox> checkbox;public:Application(std::unique_ptr<GUIFactory> f) : factory(std::move(f)) {}void createUI() {button = factory->createButton();checkbox = factory->createCheckbox();}void paint() {if (button) button->paint();if (checkbox) checkbox->paint();}
};int main() {std::string config = "Windows"; // 可以改為 "Web" 來測試std::unique_ptr<GUIFactory> factory;if (config == "Windows") {factory = std::make_unique<WindowsFactory>();} else if (config == "Web") {factory = std::make_unique<WebFactory>();}if (factory) {auto app = Application(std::move(factory));app.createUI();app.paint();}return 0;
}
二、結構型模式
1. 裝飾器模式
核心思想:動態地給一個對象添加一些額外的職責,而無需通過子類繼承。它通過創建一個包裝對象(即裝飾器)來包裹真實對象,提供了比繼承更有彈性的替代方案。
比喻:就像給一個禮物打包。你可以先裝盒子,再系絲帶,最后貼卡片。每個步驟都是在原有禮物的基礎上“裝飾”新的功能,而不是改變禮物本身。
優點:
- 無需創建大量子類即可擴展功能。
- 可以在運行時動態地添加或撤銷功能。
- 符合“開閉原則”(對擴展開放,對修改關閉)。
C++ 樣例:
我們有一個簡單的Stream
接口,我們需要動態地為其添加壓縮和加密的功能。
#include <iostream>
#include <string>// 組件接口
class Stream {
public:virtual void write(const std::string& data) = 0;virtual ~Stream() {}
};// 具體組件
class FileStream : public Stream {
public:void write(const std::string& data) override {std::cout << "Writing \"" << data << "\" to a file." << std::endl;}
};// 裝飾器基類
class StreamDecorator : public Stream {
protected:Stream* m_stream; // 持有一個組件對象的引用
public:StreamDecorator(Stream* stream) : m_stream(stream) {}virtual ~StreamDecorator() { delete m_stream; }
};// 具體裝飾器 - 壓縮
class CompressedStream : public StreamDecorator {
public:CompressedStream(Stream* stream) : StreamDecorator(stream) {}void write(const std::string& data) override {std::string compressedData = "Compressed(" + data + ")";m_stream->write(compressedData); // 調用被裝飾對象的方法}
};// 具體裝飾器 - 加密
class EncryptedStream : public StreamDecorator {
public:EncryptedStream(Stream* stream) : StreamDecorator(stream) {}void write(const std::string& data) override {std::string encryptedData = "Encrypted(" + data + ")";m_stream->write(encryptedData); // 調用被裝飾對象的方法}
};int main() {// 1. 簡單的文件流Stream* stream1 = new FileStream();stream1->write("Hello World");delete stream1;std::cout << "---------------" << std::endl;// 2. 動態添加功能:壓縮的文件流Stream* stream2 = new CompressedStream(new FileStream());stream2->write("Hello World");delete stream2;std::cout << "---------------" << std::endl;// 3. 動態添加更多功能:先加密再壓縮的文件流// 裝飾順序很重要!Stream* stream3 = new CompressedStream(new EncryptedStream(new FileStream()));stream3->write("Hello World");delete stream3;return 0;
}
輸出:
Writing "Hello World" to a file.
---------------
Writing "Compressed(Hello World)" to a file.
---------------
Writing "Compressed(Encrypted(Hello World))" to a file.
2. 代理模式
核心思想:為另一個對象提供一個替身或占位符以控制對這個對象的訪問。
常見代理類型:
- 遠程代理:為一個對象在不同的地址空間提供局部代表(例如,RPC調用)。
- 虛擬代理:根據需要創建開銷很大的對象(如圖片懶加載)。
- 保護代理:控制對原始對象的訪問權限。
- 智能引用代理:在對象被訪問時執行附加操作(如引用計數、日志記錄)。
C++ 樣例:
虛擬代理:延遲加載大圖片。
#include <iostream>
#include <string>// 抽象主題
class Image {
public:virtual void display() = 0;virtual ~Image() {}
};// 真實主題
class RealImage : public Image {
private:std::string m_filename;void loadFromDisk() {std::cout << "Loading image: " << m_filename << " (This is an expensive operation!)" << std::endl;}
public:RealImage(const std::string& filename) : m_filename(filename) {loadFromDisk();}void display() override {std::cout << "Displaying image: " << m_filename << std::endl;}
};// 代理
class ProxyImage : public Image {
private:std::string m_filename;RealImage* m_realImage; // 代理持有一個對真實對象的引用public:ProxyImage(const std::string& filename) : m_filename(filename), m_realImage(nullptr) {}~ProxyImage() { delete m_realImage; }void display() override {// 只有在需要時才創建真實對象if (m_realImage == nullptr) {m_realImage = new RealImage(m_filename);}// 委托給真實對象執行請求m_realImage->display();}
};int main() {// 創建代理時,真實對象尚未創建,沒有昂貴的加載操作Image* image = new ProxyImage("test_10MB_photo.jpg");std::cout << "Image object created. Image not loaded yet." << std::endl;// 第一次調用display,真實對象被創建和加載image->display();std::cout << std::endl;// 后續調用,真實對象已存在,直接使用std::cout << "Second display call:" << std::endl;image->display();delete image;return 0;
}
輸出:
Image object created. Image not loaded yet.
Loading image: test_10MB_photo.jpg (This is an expensive operation!)
Displaying image: test_10MB_photo.jpgSecond display call:
Displaying image: test_10MB_photo.jpg
三、行為型模式
1. 觀察者模式
核心思想:定義對象間的一種一對多的依賴關系,當一個對象(主題)的狀態發生改變時,所有依賴于它的對象(觀察者)都得到通知并被自動更新。又稱“發布-訂閱”模式。
比喻:報紙訂閱。出版社(主題)負責出版報紙。你(觀察者)向出版社訂閱后,一旦有新報紙出版,出版社就會自動送到你家。你也可以隨時取消訂閱。
C++ 樣例:
使用現代C++的特性實現。
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>// 觀察者接口
class Observer {
public:virtual void update(int temperature) = 0;virtual ~Observer() {}
};// 主題(被觀察者)
class WeatherStation {
private:int m_temperature;std::vector<Observer*> m_observers; // 存儲觀察者指針public:void registerObserver(Observer* observer) {m_observers.push_back(observer);}void removeObserver(Observer* observer) {m_observers.erase(std::remove(m_observers.begin(), m_observers.end(), observer),m_observers.end());}void notifyObservers() {for (auto observer : m_observers) {observer->update(m_temperature);}}void setTemperature(int temp) {m_temperature = temp;std::cout << "Temperature updated to: " << temp << std::endl;notifyObservers(); // 狀態改變,通知所有觀察者}
};// 具體觀察者
class Display : public Observer {
public:void update(int temperature) override {std::cout << "[Display] Current temperature is: " << temperature << "°C" << std::endl;}
};class AlertSystem : public Observer {
public:void update(int temperature) override {if (temperature > 30) {std::cout << "[AlertSystem] Warning! Temperature is too high: " << temperature << "°C" << std::endl;}}
};int main() {WeatherStation station;Display display;AlertSystem alert;// 注冊觀察者station.registerObserver(&display);station.registerObserver(&alert);// 改變主題狀態,觸發通知station.setTemperature(25);std::cout << "-------------------" << std::endl;station.setTemperature(35);// 移除一個觀察者station.removeObserver(&alert);std::cout << "-------------------" << std::endl;std::cout << "After removing alert system:" << std::endl;station.setTemperature(40);return 0;
}
輸出:
Temperature updated to: 25
[Display] Current temperature is: 25°C
[AlertSystem] Warning! Temperature is too high: 25°C
-------------------
Temperature updated to: 35
[Display] Current temperature is: 35°C
[AlertSystem] Warning! Temperature is too high: 35°C
-------------------
After removing alert system:
Temperature updated to: 40
[Display] Current temperature is: 40°C
2. 策略模式
核心思想:定義一系列算法,將每個算法封裝起來,并且使它們可以互相替換。策略模式讓算法的變化獨立于使用算法的客戶。
比喻:出行方式。去機場是一個目標(Context),你可以選擇不同的策略(Strategy):坐公交、打車、坐地鐵。你可以根據時間、金錢等因素輕松替換策略,而改變“去機場”這個行為本身。
優點:
- 避免使用多重條件判斷語句(if-else/switch-case)。
- 算法可以自由切換和擴展。
- 符合“開閉原則”。
C++ 樣例:
#include <iostream>
#include <memory>
#include <vector>// 策略接口
class PaymentStrategy {
public:virtual void pay(int amount) = 0;virtual ~PaymentStrategy() {}
};// 具體策略
class CreditCardPayment : public PaymentStrategy {
private:std::string m_name;std::string m_cardNumber;
public:CreditCardPayment(const std::string& name, const std::string& cardNumber): m_name(name), m_cardNumber(cardNumber) {}void pay(int amount) override {std::cout << "Paid $" << amount << " using Credit Card (" << m_cardNumber << ")" << std::endl;}
};class PayPalPayment : public PaymentStrategy {
private:std::string m_email;
public:PayPalPayment(const std::string& email) : m_email(email) {}void pay(int amount) override {std::cout << "Paid $" << amount << " using PayPal (" << m_email << ")" << std::endl;}
};class CryptoPayment : public PaymentStrategy {
private:std::string m_walletAddress;
public:CryptoPayment(const std::string& address) : m_walletAddress(address) {}void pay(int amount) override {std::cout << "Paid $" << amount << " using Crypto (Address: " << m_walletAddress << ")" << std::endl;}
};// 上下文(Context)
class ShoppingCart {
private:std::vector<std::string> m_items;std::unique_ptr<PaymentStrategy> m_paymentStrategy;public:void addItem(const std::string& item) {m_items.push_back(item);}int calculateTotal() {// 簡化計算,假設每件商品10美元return m_items.size() * 10;}void setPaymentStrategy(std::unique_ptr<PaymentStrategy> strategy) {m_paymentStrategy = std::move(strategy);}void checkout() {int amount = calculateTotal();if (m_paymentStrategy) {m_paymentStrategy->pay(amount);std::cout << "Checkout successful! Enjoy your items." << std::endl;} else {std::cout << "Please set a payment method before checkout." << std::endl;}}
};int main() {ShoppingCart cart;cart.addItem("Book");cart.addItem("Laptop");cart.addItem("Mouse");int total = cart.calculateTotal();std::cout << "Total: $" << total << std::endl;// 用戶在運行時選擇支付策略int choice = 2; // 可以來自用戶輸入if (choice == 1) {cart.setPaymentStrategy(std::make_unique<CreditCardPayment>("John Doe", "1234-5678-9012-3456"));} else if (choice == 2) {cart.setPaymentStrategy(std::make_unique<PayPalPayment>("john.doe@example.com"));} else if (choice == 3) {cart.setPaymentStrategy(std::make_unique<CryptoPayment>("0xABC123..."));}cart.checkout();return 0;
}
輸出:
Total: $30
Paid $30 using PayPal (john.doe@example.com)
Checkout successful! Enjoy your items.
注:以上內容大部分由DeepSeek生成