發(fā)布培訓(xùn)的免費網(wǎng)站模板產(chǎn)品網(wǎng)絡(luò)推廣的方法
目錄
前言
一、面向?qū)ο蟮膬深悓ο髣?chuàng)建問題
二、解決問題
三、工廠模式代碼示例
四、工廠模式的核心功能
五、工廠模式的應(yīng)用場景
六、工廠模式的實現(xiàn)與結(jié)構(gòu)
七、工廠模式的優(yōu)缺點
八、工廠模式的擴展與優(yōu)化
九、總結(jié)
前言
????????在面向?qū)ο笙到y(tǒng)設(shè)計中,開發(fā)者常常面臨兩類典型的對象創(chuàng)建問題。為了解決這些問題,工廠模式(Factory Pattern)應(yīng)運而生,成為了一種廣泛應(yīng)用的解決方案。本文將詳細探討這兩類問題,并分析工廠模式的功能、實現(xiàn)及其在實際開發(fā)中的應(yīng)用。
一、面向?qū)ο蟮膬深悓ο髣?chuàng)建問題
(1)抽象基類與多態(tài)帶來的問題
????????為了提高代碼的內(nèi)聚性(Cohesion)和降低耦合性(Coupling),我們通常會抽象出類的公共接口,形成抽象基類或接口。通過聲明指向基類的指針來指向?qū)嶋H子類的實現(xiàn),從而實現(xiàn)多態(tài)性。然而,這種做法也帶來了以下問題:
????????子類名稱依賴:客戶端代碼必須知道具體子類的名稱。隨著系統(tǒng)復(fù)雜度的增加,命名沖突和可讀性問題變得難以處理,尤其是當開發(fā)者有不同的命名偏好時。
????????擴展性與維護困難:每次使用子類時都需要顯式地實例化(如 `new ×××`),導(dǎo)致代碼重復(fù),擴展性和維護性變差。
(2)父類無法確定具體子類的問題
????????在某些情況下,父類并不知道具體要實例化哪一個子類。例如,假設(shè)在類 A 中需要使用類 B,而 B 是一個抽象父類。在類 A 中無法確定具體實例化哪一個 B 的子類,但類 A 的子類 D 可以知道。此時,在類 A 中無法直接使用類似 `new ×××` 的語句,因為具體類型未知。
二、解決問題
????????我們通常使用工廠模式(Factory Pattern)來解決上述兩個問題。在處理第一個問題時,常見的做法是聲明一個創(chuàng)建對象的接口,并將對象的創(chuàng)建過程封裝起來。此時,工廠類就像一個真正的“生產(chǎn)工廠”,負責(zé)生成所需的對象。
????????而在第二個問題中,我們需要提供一個對象創(chuàng)建的接口,并在子類中實現(xiàn)具體的創(chuàng)建邏輯,因為只有子類能夠決定實例化哪個具體類。?
圖1
????????圖1展示了第一種情況的工廠模式結(jié)構(gòu)示意圖。
????????這種模式在系統(tǒng)開發(fā)中經(jīng)常被使用,但這并不是工廠模式的最大優(yōu)勢所在(因為這個問題可以通過其他方式解決)。工廠模式不僅僅提供了創(chuàng)建對象的接口,更重要的是它延遲了子類的實例化(即第二個問題)。以下是這種情況的工廠模式結(jié)構(gòu)示意圖:?
圖2
????????圖2展示了第二種情況的工廠模式結(jié)構(gòu)示意圖。圖2中的關(guān)鍵在于,工廠模式的應(yīng)用并不僅限于封裝對象的創(chuàng)建,而是將對象的創(chuàng)建過程放到子類中實現(xiàn):工廠類只提供對象創(chuàng)建的接口,而具體的實現(xiàn)則由其子類(如 `ConcreteFactory`)完成。這正是圖2與圖1的主要區(qū)別所在。
三、工廠模式代碼示例
Product.h
#ifndef PRODUCT_H
#define PRODUCT_H#include <iostream>// 抽象基類 Product
class Product {
public:virtual ~Product() = 0; // 純虛析構(gòu)函數(shù)
protected:Product() = default; // 默認構(gòu)造函數(shù),限制為派生類訪問
};// 具體派生類 ConcreteProduct
class ConcreteProduct : public Product {
public:ConcreteProduct();~ConcreteProduct() override;
};#endif // PRODUCT_H
Product.cpp
#include "Product.h"// 純虛析構(gòu)函數(shù)的實現(xiàn)
Product::~Product() = default;// ConcreteProduct 實現(xiàn)
ConcreteProduct::ConcreteProduct() {std::cout << "ConcreteProduct created." << std::endl;
}ConcreteProduct::~ConcreteProduct() {std::cout << "ConcreteProduct destroyed." << std::endl;
}
Factory.h
#ifndef FACTORY_H
#define FACTORY_Hclass Product;// 抽象基類 Factory
class Factory {
public:virtual ~Factory() = 0; // 純虛析構(gòu)函數(shù)virtual Product* CreateProduct() = 0; // 工廠方法
protected:Factory() = default; // 默認構(gòu)造函數(shù),限制為派生類訪問
};// 具體派生類 ConcreteFactory
class ConcreteFactory : public Factory {
public:ConcreteFactory();~ConcreteFactory() override;Product* CreateProduct() override;
};#endif // FACTORY_H
Factory.cpp
#include "Factory.h"
#include "Product.h"
#include <iostream>// 純虛析構(gòu)函數(shù)的實現(xiàn)
Factory::~Factory() = default;// ConcreteFactory 實現(xiàn)
ConcreteFactory::ConcreteFactory() {std::cout << "ConcreteFactory created." << std::endl;
}ConcreteFactory::~ConcreteFactory() {std::cout << "ConcreteFactory destroyed." << std::endl;
}Product* ConcreteFactory::CreateProduct() {return new ConcreteProduct();
}
main.cpp
#include "Factory.h"
#include "Product.h"
#include <iostream>int main() {// 創(chuàng)建工廠對象Factory* fac = new ConcreteFactory();// 使用工廠創(chuàng)建產(chǎn)品對象Product* p = fac->CreateProduct();// 釋放對象delete p;delete fac;return 0;
}
????????在示例代碼中,工廠模式(Factory Pattern)被用來解決父類無法確定具體要實例化哪一個子類的問題。至于為創(chuàng)建對象提供接口的問題,可以通過在工廠類中附加相應(yīng)的創(chuàng)建操作來實現(xiàn),例如添加 `Create***Product()` 方法。
????????工廠模式(Factory Pattern)在實際開發(fā)中應(yīng)用非常廣泛,尤其是在面向?qū)ο笙到y(tǒng)中,開發(fā)者經(jīng)常面臨對象創(chuàng)建的問題:需要創(chuàng)建的類數(shù)量非常多。工廠模式通過提供創(chuàng)建對象的接口封裝(第一個功能)以及將類的實例化推遲到子類(第二個功能),部分地解決了這些實際問題。一個典型的例子是筆者在開發(fā) VisualCMCS 系統(tǒng)的語義分析模塊時,由于需要為文法中的每個非終結(jié)符構(gòu)造一個處理類,因此對象的創(chuàng)建非常頻繁。采用工廠模式后,系統(tǒng)的可讀性和維護性都變得更加優(yōu)雅(elegant)。
????????然而,工廠模式也帶來至少以下兩個問題: ?
????????(1)接口封閉性問題:如果為每一個具體的 `ConcreteProduct` 類的實例化提供一個單獨的函數(shù)體,那么我們可能不得不在系統(tǒng)中不斷添加新的方法來處理這些新創(chuàng)建的 `ConcreteProduct`。這樣,工廠接口就難以做到封閉(Close)。雖然可以通過創(chuàng)建一個工廠的子類來利用多態(tài)性實現(xiàn)這一點,但這也會導(dǎo)致需要新增一個類作為代價。 ?
????????(2)參數(shù)化工廠方法:在實現(xiàn)中,我們可以通過參數(shù)化工廠方法,即給 `FactoryMethod()` 傳遞一個參數(shù)來決定創(chuàng)建哪一個具體的 `Product`(實際上,筆者在 VisualCMCS 中也采用了這種方式)。此外,還可以通過模板化來避免第一個問題中的子類創(chuàng)建,具體方法是將具體的 `Product` 類作為模板參數(shù),實現(xiàn)起來也非常簡單。 ?
????????可以看出,工廠模式為對象的創(chuàng)建提供了一種優(yōu)秀的實現(xiàn)策略。然而,工廠模式僅限于處理同一類別的類(即這些類有一個共同的基類)。如果我們需要為不同類別的類提供一個對象創(chuàng)建的接口,那么就需要使用抽象工廠模式(AbstractFactory)了。抽象工廠模式我們下節(jié)再講。
四、工廠模式的核心功能
工廠模式通過以下兩個核心功能,解決了上述問題:
(1)定義創(chuàng)建對象的接口,封裝對象的創(chuàng)建過程:工廠模式將對象的創(chuàng)建過程抽象化,客戶端代碼只需依賴工廠接口,而無需關(guān)心具體類的實例化細節(jié)。
(2)將具體類的實例化延遲到子類:工廠模式允許子類決定實例化哪個具體類,從而將對象創(chuàng)建的決策推遲到運行時。
五、工廠模式的應(yīng)用場景
(1)封裝對象創(chuàng)建
????????在第一個問題中,工廠模式通過聲明一個創(chuàng)建對象的接口,封裝了對象的創(chuàng)建過程。工廠類類似于一個“生產(chǎn)對象”的工廠,客戶端代碼只需調(diào)用工廠接口,而無需直接依賴具體類。
(2)延遲實例化到子類
????????在第二個問題中,工廠模式將具體類的實例化延遲到子類。父類只需定義創(chuàng)建對象的接口,而具體實現(xiàn)則由子類完成。這種方式不僅解決了父類無法確定具體子類的問題,還提高了代碼的靈活性和可擴展性。
六、工廠模式的實現(xiàn)與結(jié)構(gòu)
(1)簡單工廠模式
????????簡單工廠模式通過一個工廠類封裝對象的創(chuàng)建過程??蛻舳舜a只需調(diào)用工廠類的方法,即可獲取所需對象。然而,這種模式的擴展性較差,新增產(chǎn)品類型時需要修改工廠類。
(2)工廠方法模式
????????工廠方法模式將對象的創(chuàng)建延遲到子類。抽象工廠類定義創(chuàng)建對象的接口,具體工廠類負責(zé)實例化具體產(chǎn)品。這種方式符合開閉原則,新增產(chǎn)品類型時只需添加新的工廠類,而無需修改現(xiàn)有代碼。
(3)抽象工廠模式
????????抽象工廠模式用于創(chuàng)建一系列相關(guān)或依賴的對象。它為不同產(chǎn)品族提供創(chuàng)建接口,而具體工廠類負責(zé)實例化特定產(chǎn)品族中的對象。這種方式適用于需要創(chuàng)建多個不同類型對象的場景。
七、工廠模式的優(yōu)缺點
(1)優(yōu)點
????????解耦:將對象創(chuàng)建與使用分離,降低了代碼的耦合性。
????????擴展性:新增產(chǎn)品類型時無需修改現(xiàn)有代碼,符合開閉原則。
????????靈活性:通過多態(tài)將對象創(chuàng)建延遲到運行時,支持動態(tài)決策。
(2)缺點
????????類數(shù)量增加:每新增一個產(chǎn)品類型,可能需要添加新的工廠類,導(dǎo)致類數(shù)量膨脹。
????????復(fù)雜性增加:工廠模式的實現(xiàn)可能增加系統(tǒng)的復(fù)雜性,尤其是抽象工廠模式。
八、工廠模式的擴展與優(yōu)化
(1)參數(shù)化工廠方法
????????通過為工廠方法傳遞參數(shù),決定具體創(chuàng)建哪一個產(chǎn)品。這種方式可以減少工廠類的數(shù)量,但可能增加工廠方法的復(fù)雜性。
(2)模板化工廠
????????將具體產(chǎn)品類作為模板參數(shù),避免為每個產(chǎn)品類型創(chuàng)建新的工廠類。這種方式在 C++ 等支持模板的語言中實現(xiàn)較為簡單。
(3)抽象工廠模式
????????當需要為不同類的產(chǎn)品提供創(chuàng)建接口時,可以使用抽象工廠模式。抽象工廠模式為每個產(chǎn)品族提供一個創(chuàng)建接口,適用于復(fù)雜對象創(chuàng)建的場景。
九、總結(jié)
????????工廠模式是面向?qū)ο笤O(shè)計中解決對象創(chuàng)建問題的經(jīng)典模式。它通過封裝對象創(chuàng)建過程和延遲實例化到子類,有效地降低了代碼的耦合性,提高了系統(tǒng)的擴展性和靈活性。盡管工廠模式可能增加類的數(shù)量和系統(tǒng)的復(fù)雜性,但其在解耦和支持變化方面的優(yōu)勢使其在實際開發(fā)中得到了廣泛應(yīng)用。對于需要頻繁創(chuàng)建對象的系統(tǒng),工廠模式無疑是一種優(yōu)雅且高效的解決方案。
????????參考學(xué)習(xí)書籍:設(shè)計模式精解-GoF 23 種設(shè)計模式解析