文章目錄
- C++ 工廠模式
- 引言
- 一、簡單工廠模式
- 概念
- 實現步驟
- 示例代碼
- 優缺點
- 二、工廠方法模式
- 概念
- 實現步驟
- 示例代碼
- 優缺點
- 三、抽象工廠模式
- 概念
- 實現步驟
- 示例代碼
- 優缺點
C++ 工廠模式
引言
在 C++ 編程中,對象的創建是一個常見且基礎的操作。然而,當項目規模逐漸增大,對象的創建邏輯變得復雜時,直接在代碼中使用 new
關鍵字創建對象會帶來諸多問題,比如代碼的可維護性變差、難以擴展等。工廠模式應運而生,它為對象的創建提供了一種更加靈活、可擴展的解決方案。本文將詳細介紹 C++ 中的工廠模式,包括簡單工廠模式、工廠方法模式和抽象工廠模式,并通過具體的例子幫助大家理解。
一、簡單工廠模式
概念
簡單工廠模式是工廠模式的基礎版本,它定義了一個工廠類,該類可以根據傳入的參數決定創建并返回哪種產品類的實例。簡單來說,就是把對象的創建邏輯封裝在一個工廠類中。
實現步驟
- 定義產品基類:創建一個抽象的產品基類,所有具體產品類都要繼承這個基類。
- 創建具體產品類:實現產品基類的接口,創建具體的產品類。
- 創建工廠類:在工廠類中定義一個創建產品的方法,根據傳入的參數決定創建哪種具體產品。
示例代碼
#include<iostream>
#include<memory>// 定義水果抽象基類,包含純虛函數 name
class Fruit{public:// 純虛函數,用于輸出水果名稱,派生類需實現virtual void name()=0;
};// 蘋果類,繼承自 Fruit 類
class Apple:public Fruit{public:// 重寫基類的 name 函數,輸出蘋果名稱void name() override{std::cout<<"Apple"<<std::endl;}
};// 香蕉類,繼承自 Fruit 類
class Banana:public Fruit{public:// 重寫基類的 name 函數,輸出香蕉名稱void name() override{std::cout<<"Banana"<<std::endl;}
};// 工廠類,用于創建不同類型的水果對象
class Factory{public:// 靜態方法,根據傳入的水果名稱創建對應的水果對象static std::unique_ptr<Fruit> createFruit(std::string fruit_name){if(fruit_name=="apple"){// 創建蘋果對象并返回其 unique_ptrreturn std::unique_ptr<Fruit>(new Apple());}else if(fruit_name=="banana"){// 創建香蕉對象并返回其 unique_ptrreturn std::unique_ptr<Fruit>(new Banana());}else{// 若名稱不匹配,返回空指針return nullptr;}}
};int main()
{// 使用工廠類創建蘋果對象std::unique_ptr<Fruit> fruit = Factory::createFruit("apple");// 調用蘋果對象的 name 函數輸出名稱fruit->name(); // 使用工廠類創建香蕉對象fruit = Factory::createFruit("banana");// 調用香蕉對象的 name 函數輸出名稱fruit->name();// 再次使用工廠類創建蘋果對象fruit = Factory::createFruit("apple");return 0;
}
優缺點
- 優點:實現簡單,將對象的創建和使用分離,提高了代碼的可維護性。
- 缺點:工廠類職責過重,違反了開閉原則(對擴展開放,對修改關閉)。如果需要新增產品,就需要修改工廠類的代碼。
二、工廠方法模式
概念
工廠方法模式是在簡單工廠模式的基礎上進行了改進,它將創建對象的具體邏輯延遲到子類中實現。定義一個創建對象的抽象方法,讓子類決定實例化哪個具體產品類。
實現步驟
- 定義產品基類:同簡單工廠模式。
- 創建具體產品類:同簡單工廠模式。
- 定義抽象工廠類:定義一個抽象的工廠類,其中包含一個抽象的創建產品的方法。
- 創建具體工廠類:繼承抽象工廠類,實現創建產品的方法,決定創建哪種具體產品。
示例代碼
#include<iostream>
#include<memory>// 定義抽象基類 Fruit,包含純虛函數 name
// 任何繼承自該類的具體水果類都必須實現 name 函數
class Fruit {
public:// 純虛函數,用于輸出水果名稱virtual void name() = 0;
};// 定義 Apple 類,繼承自 Fruit 類
class Apple : public Fruit {
public:// 重寫基類的純虛函數 name,輸出蘋果名稱void name() override {std::cout << "Apple" << std::endl;}
};// 定義 Banana 類,繼承自 Fruit 類
class Banana : public Fruit {
public:// 重寫基類的純虛函數 name,輸出香蕉名稱void name() override {std::cout << "Banana" << std::endl;}
};// 定義抽象工廠類 Factory,包含純虛函數 create
// 具體的工廠類需要實現該函數來創建水果對象
class Factory {
public:// 純虛函數,用于創建水果對象virtual std::shared_ptr<Fruit> create() = 0;
};// 定義 AppleFactory 類,繼承自 Factory 類
class AppleFactory : public Factory {
public:// 重寫基類的純虛函數 create,創建蘋果對象std::shared_ptr<Fruit> create() override {return std::make_shared<Apple>();}
};// 定義 BananaFactory 類,繼承自 Factory 類
class BananaFactory : public Factory {
public:// 重寫基類的純虛函數 create,創建香蕉對象std::shared_ptr<Fruit> create() override {return std::make_shared<Banana>();}
};int main() {// 創建一個指向 AppleFactory 的智能指針std::shared_ptr<Factory> fruit_factory(new AppleFactory());// 調用工廠的 create 方法創建蘋果對象std::shared_ptr<Fruit> fruit = fruit_factory->create();// 調用水果對象的 name 方法輸出名稱fruit->name();// 重置工廠指針,指向 BananaFactoryfruit_factory.reset(new BananaFactory());// 調用新工廠的 create 方法創建香蕉對象fruit = fruit_factory->create();// 調用水果對象的 name 方法輸出名稱fruit->name();return 0;
}
優缺點
- 優點:符合開閉原則,當需要新增產品時,只需要新增具體產品類和對應的具體工廠類,不需要修改現有代碼。
- 缺點:類的數量會增多,增加了系統的復雜度。
三、抽象工廠模式
概念
抽象工廠模式:工廠方法模式通過引入工廠等級結構,解決了簡單工廠模式中工廠類職責太重的問題。但由于工廠方法模式中的每個工廠只生產一類產品,可能會導致系統中存在大量的工廠類,勢必會增加系統的開銷。此時,我們可以考慮將一些相關的產品組成一個產品族(位于不同產品等級結構中功能相關聯的產品組成的家族),由同一個工廠來統一生產,這就是抽象工廠模式的基本思想。
實現步驟
- 定義產品族的抽象基類:為每個產品族定義一個抽象基類。
- 創建具體產品類:實現每個產品族的具體產品類。
- 定義抽象工廠類:定義一個抽象的工廠類,其中包含多個創建不同產品的抽象方法。
- 創建具體工廠類:繼承抽象工廠類,實現創建不同產品的方法,決定創建哪些具體產品。
示例代碼
#include<iostream>
#include<memory>// 水果抽象基類,定義了輸出水果名稱的純虛函數
class Fruit {
public:virtual void name() = 0;
};// 蘋果類,繼承自 Fruit 類,實現了輸出蘋果名稱的方法
class Apple : public Fruit {
public:void name() override {std::cout << "Apple" << std::endl;}
};// 香蕉類,繼承自 Fruit 類,實現了輸出香蕉名稱的方法
class Banana : public Fruit {
public:void name() override {std::cout << "Banana" << std::endl;}
};// 動物抽象基類,定義了輸出動物名稱的純虛函數
class Animal {
public:virtual void name() = 0;
};// 羊類,繼承自 Animal 類,實現輸出名稱方法
class Lamb : public Animal {
public:void name() override {std::cout << "Lamb" << std::endl;}
};// 狗類,繼承自 Animal 類,實現了輸出狗名稱的方法
class Dog : public Animal {
public:void name() override {std::cout << "Dog" << std::endl;}
};// 抽象工廠類,定義了獲取水果和動物對象的純虛函數
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<Fruit> getFruit(const std::string& name);virtual std::shared_ptr<Animal> getAnimal(const std::string& name);
};// 動物工廠類,繼承自 Factory 類,實現了獲取動物對象的方法,獲取水果對象返回空指針
class AnimalFactory : public Factory {
public:virtual std::shared_ptr<Fruit> getFruit(const std::string& name);virtual std::shared_ptr<Animal> getAnimal(const std::string& name);
};// 工廠管理類,提供靜態方法根據名稱創建對應的工廠對象
class FactoryManager {
public:static std::shared_ptr<Factory> creaete(const std::string& name);
};int main() {// 通過工廠管理類創建水果工廠對象std::shared_ptr<Factory> fruit_factory = FactoryManager::creaete("fruit");// 從水果工廠獲取蘋果對象并輸出名稱std::shared_ptr<Fruit> fruit = fruit_factory->getFruit("apple");fruit->name();// 從水果工廠獲取香蕉對象并輸出名稱fruit = fruit_factory->getFruit("banana");fruit->name();return 0;
}
優缺點
- 優點:將一系列相關的產品對象的創建封裝在一起,保證了產品之間的一致性,同時也符合開閉原則。
- 缺點:實現復雜,當產品族需要增加新的產品時,需要修改抽象工廠類和所有具體工廠類的代碼。