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