設(shè)計模式之簡單工廠模式、工廠模式、抽象工廠模式的對比
前言:
設(shè)計模式已經(jīng)經(jīng)歷了很長一段時間的發(fā)展,它們提供了軟件開發(fā)過程中面臨的一般問題的最佳解決方案。學(xué)習(xí)這些模式有助于經(jīng)驗不足的開發(fā)人員通過一種簡單快捷的方式來學(xué)習(xí)軟件設(shè)計。
一般我們會說設(shè)計模式一共有23種,總體來說設(shè)計模式分為三大類:
創(chuàng)建型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。
結(jié)構(gòu)型模式,共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
行為型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責(zé)任鏈模式、命令模式、備忘錄模式、狀態(tài)模式、訪問者模式、中介者模式、解釋器模式。
今天主要是分析 簡單工廠模式、工廠模式和抽象工廠模式的區(qū)別,所以這里就簡單介紹一下設(shè)計模式的概念。
網(wǎng)上的很多資料都是在闡述著:工廠模式的好處就是解耦。相信大家對解耦這個詞也不陌生,那解耦究竟有什么好處呢?
- 1.為了提高內(nèi)聚(Cohesion)和松耦合(Coupling),我們經(jīng)常會抽象出一些類的公共接口以形成抽象基類或者接口。這樣我們可以通過聲明一個指向基類的指針來指向?qū)嶋H的子類實現(xiàn),達(dá)到了多態(tài)的目的。這里很容易出現(xiàn)的一個問題 n 多的子類繼承自抽象基類,我們不得不在每次要用到子類的地方就編寫諸如 new ×××;的代碼。這里帶來兩個問題:
客戶程序員必須知道實際子類的名稱(當(dāng)系統(tǒng)復(fù)雜后,命名將是一個很不好處理的問題,為了處理可能的名字沖突,有的命名可能并不是具有很好的可讀性和可記憶性,就姑且不論不同程序員千奇百怪的個人偏好了)。程序的擴(kuò)展性和維護(hù)變得越來越困難。
- 2.還有一種情況就是在父類中并不知道具體要實例化哪一個具體的子類。這里的意思為:假設(shè)我們在類 A 中要使用到類 B,B 是一個抽象父類,在 A 中并不知道具體要實例化那一個 B 的子類,但是在類 A 的子類 D 中是可以知道的。在 A 中我們沒有辦法直接使用類似于 new ×××的語句,因為根本就不知道×××是什么。
以上兩個問題也就引出了工廠模式的兩個最重要的功能:定義創(chuàng)建對象的接口,封裝了對象的創(chuàng)建;使得具體化類的工作延遲到了子類中。
對于工廠模式,為了使其能更好的解決多種情況的問題,將其分為三類:簡單工廠模式(Simple Factory),工廠方法模式(Factory Method),抽象工廠模式(Abstract Factory)。GOAT 經(jīng)常使用會遇到一些設(shè)計模式的使用,但是很少去細(xì)究里面的區(qū)別,這把就讓我來大家分享一下,我認(rèn)知中的這三種工廠模式。
簡單工廠模式
我們把被創(chuàng)建的對象稱為“產(chǎn)品”,把創(chuàng)建產(chǎn)品的對象稱為“工廠”。如果要創(chuàng)建的產(chǎn)品不多,只要一個工廠類就可以完成,這種模式叫“簡單工廠模式”。
結(jié)構(gòu)定義:
是由一個工廠對象決定創(chuàng)建出哪一種產(chǎn)品類的實例。簡單工廠模式中包含的角色及其相應(yīng)的職責(zé)如下:
工廠角色(Creator):這是簡單工廠模式的核心,由它負(fù)責(zé)創(chuàng)建所有的類的內(nèi)部邏輯。當(dāng)然工廠類必須能夠被外界調(diào)用,創(chuàng)建所需要的產(chǎn)品對象。
抽象(Product)產(chǎn)品角色:簡單工廠模式所創(chuàng)建的所有對象的父類,注意,這里的父類可以是接口也可以是抽象類,它負(fù)責(zé)描述所有實例所共有的公共接口。
具體產(chǎn)品(Concrete Product)角色:簡單工廠所創(chuàng)建的具體實例對象,這些具體的產(chǎn)品往往都擁有共同的父類。
定義一個創(chuàng)建產(chǎn)品對象的工廠接口,將產(chǎn)品對象的實際創(chuàng)建工作推遲到具體子工廠類當(dāng)中。這滿足創(chuàng)建型模式中所要求的“創(chuàng)建與使用相分離”的特點。
結(jié)構(gòu)圖如下
范例如下:
C++實現(xiàn)
- #include <iostream>
- using namespace std;
- enum Product_Type
- {
- Product1_,
- Product2_,
- };
- class AbstractProduct //抽象(Product)產(chǎn)品角色
- {
- public:
- AbstractProduct() {}
- virtual ~AbstractProduct() {}
- virtual void Show() = 0;
- };
- class Product1 : public AbstractProduct //具體產(chǎn)品(Concrete Product)角色
- {
- private:
- /* data */
- public:
- Product1(/* args */);
- ~Product1();
- void Show()
- {
- std::cout<< "product1"<<std::endl;
- }
- };
- Product1::Product1()
- {
- }
- Product1::~Product1()
- {
- }
- class Product2 : public AbstractProduct //具體產(chǎn)品(Concrete Product)角色
- {
- private:
- /* data */
- public:
- void Show()
- {
- std::cout<< "product2"<<std::endl;
- }
- };
- class Factory //工廠角色(Creator)
- {
- public:
- AbstractProduct *CreateProduct(Product_Type type)
- {
- switch (type)
- {
- case Product1_/* constant-expression */:
- /* code */
- return new Product1();
- case Product2_:
- return new Product2();
- default:
- return NULL;
- }
- }
- };
- int main(int argc, char **argv)
- {
- Factory *new_factory = new Factory();
- AbstractProduct *new_product1 = new_factory->CreateProduct(Product1_);
- new_product1->Show();
- AbstractProduct *new_product2 = new_factory->CreateProduct(Product2_);
- new_product2->Show();
- delete new_factory,new_product1,new_product2;
- new_factory = NULL;
- new_product1 = NULL;
- new_product2 = NULL;
- }
python實現(xiàn)
- #!/usr/bin/python3
- from enum import Enum
- ProducType = Enum(('ProducType'),('product1_','product2_','product_3'))
- class AbstractProduct(object):
- def show(self):
- pass
- class Product1(AbstractProduct):
- def show(self):
- print("Product1")
- class Product2(AbstractProduct):
- def show(self):
- print("Product2")
- class AbcFactory(object):
- def crete_product(self):
- pass
- class Factory(AbcFactory):
- def crete_product(self,type):
- product_type = {
- ProducType.product1_ : Product1(),
- ProducType.product2_ : Product2()
- }
- return product_type.get(type,None)
- if __name__ == "__main__":
- new_factory = Factory()
- product1 = new_factory.crete_product(ProducType.product1_)
- product1.show()
- product2 = new_factory.crete_product(ProducType.product2_)
- product2.show()
我們只需要調(diào)用不同的成員函數(shù),工廠就幫我們實例化出想要的對象,利用上轉(zhuǎn)型對象,返回父類的方式實現(xiàn)了結(jié)果。可以發(fā)現(xiàn)簡單工廠模式代碼簡單,但不符合OCP(面向?qū)ο笤O(shè)計的基本原則之一 OCP(開閉原則):一個軟件的實體應(yīng)當(dāng)對擴(kuò)展開放,對修改關(guān)閉)。
總結(jié) :
1、簡單工廠模式最大的優(yōu)點在于工廠類中可以判斷客戶的的選擇來動態(tài)實例化相關(guān)的類,對于客戶端來說,去除了具體產(chǎn)品的依賴。
2、缺點就是:很明顯工廠類集中了對所有實例創(chuàng)建的邏輯,如果我們要新增子類或者改變方法的話,就得每次都修改工廠類里面的代碼,工廠類中的代碼就會十分臃腫,這就等于說我們不進(jìn)開放了擴(kuò)展,還開放了修改,這樣就違反了開放-封閉原則。
你可能在不知不覺中已經(jīng)用到過這種模式了,但簡單工廠模式并不屬于23種設(shè)計模式之一,下面介紹他的改進(jìn)版本:工廠方法模式。
工廠模式
工廠方法模式是一種創(chuàng)建型設(shè)計模式, 其在父類中提供一個創(chuàng)建對象的方法, 允許子類決定實例化對象的類型。
工廠方法模式的結(jié)構(gòu)組成:
抽象工廠類廠(AbstractFactory):工廠方法模式的核心類,提供創(chuàng)建具體產(chǎn)品的接口,由具體工廠類實現(xiàn)。
具體工廠類(Producer):繼承于抽象工廠,實現(xiàn)創(chuàng)建對應(yīng)具體產(chǎn)品對象的方式。
抽象產(chǎn)品類(Factory):它是具體產(chǎn)品繼承的父類(基類)。
具體產(chǎn)品類(Factory1):具體工廠所創(chuàng)建的對象,就是此類。
C++實現(xiàn)
- #include <iostream>
- using namespace std;
- class AbstractProduct
- {
- public:
- AbstractProduct() {}
- virtual ~AbstractProduct() {}
- virtual void Show() = 0;
- };
- class Product1 : public AbstractProduct
- {
- private:
- /* data */
- public:
- Product1(/* args */);
- ~Product1();
- void Show()
- {
- std::cout<< "product1"<<std::endl;
- }
- };
- Product1::Product1(/* args */)
- {
- }
- Product1::~Product1()
- {
- }
- class Product2 : public AbstractProduct
- {
- private:
- /* data */
- public:
- void Show()
- {
- std::cout<< "product2"<<std::endl;
- }
- };
- class Factory
- {
- public:
- virtual ~Factory(){};
- virtual AbstractProduct *CreateProduct() = 0;
- };
- class Factory1 : Factory
- {
- public:
- AbstractProduct * CreateProduct(void)
- {
- return new Product1();
- }
- };
- class Factory2 :Factory
- {
- public:
- AbstractProduct * CreateProduct(void)
- {
- return new Product2();
- }
- };
- int main(int argc, char **argv)
- {
- Factory1 *new_factory = new Factory1();
- AbstractProduct *new_product1 = new_factory->CreateProduct();
- new_product1->Show();
- delete new_factory;
- new_factory = NULL;
- Factory2 * new_factory2 = new Factory2();
- AbstractProduct *new_product2 = new_factory2->CreateProduct();
- new_product2->Show();
- delete new_factory2;
- new_factory2 = NULL;
- }
python實現(xiàn)
- #!/usr/bin/python3
- class AbstractProduct(object):
- def show(self):
- pass
- class Product1(AbstractProduct):
- def show(self):
- print("Product1")
- class Product2(AbstractProduct):
- def show(self):
- print("Product2")
- class Factory(object):
- def create_product(self):
- pass
- class Factory1(Factory):
- def create_product(self):
- return Product1()
- class Factory2(Factory):
- def create_product(self):
- return Product2()
- if __name__ == "__main__":
- new_product1 = Factory1().create_product()
- new_product1.show()
- new_product2 = Factory2().create_product()
- new_product2.show()
工廠方法模式優(yōu)缺點
- 1.你可以避免創(chuàng)建者和具體產(chǎn)品之間的緊密耦合。
- 2.單一職責(zé)原則。你可以將產(chǎn)品創(chuàng)建代碼放在程序的單一位置, 從而使得代碼更容易維護(hù)。
- 3.開閉原則。無需更改現(xiàn)有客戶端代碼, 你就可以在程序中引入新的產(chǎn)品類型。
- 4.應(yīng)用工廠方法模式需要引入許多新的子類, 代碼可能會因此變得更復(fù)雜。最好的情況是將該模式引入創(chuàng)建者類的現(xiàn)有層次結(jié)構(gòu)中。
抽象工廠模式
抽象工廠模式是一種創(chuàng)建型設(shè)計模式, 它能創(chuàng)建一系列相關(guān)的對象, 而無需指定其具體類。是更多一重的工廠模式中。
結(jié)構(gòu)定義(類似工廠模式):
抽象工廠類廠(AbstractFactory):工廠方法模式的核心類,提供創(chuàng)建具體產(chǎn)品的接口,由具體工廠類實現(xiàn)。
具體工廠類(Producer):繼承于抽象工廠,實現(xiàn)創(chuàng)建對應(yīng)具體產(chǎn)品對象的方式。
抽象產(chǎn)品類(Factory):它是具體產(chǎn)品繼承的父類(基類)。
具體產(chǎn)品類(Factory1):具體工廠所創(chuàng)建的對象,就是此類。
結(jié)構(gòu)圖如下
C++實現(xiàn)
- #include <iostream>
- using namespace std;
- class AbstractProductA
- {
- public:
- AbstractProductA() {}
- virtual ~AbstractProductA() {}
- virtual void Show() = 0;
- virtual void Disp() = 0;
- };
- class ProductA1 : public AbstractProductA
- {
- private:
- /* data */
- public:
- ProductA1(){}
- ~ProductA1(){}
- void Show()
- {
- std::cout<< "productA1 show"<<std::endl;
- }
- void Disp()
- {
- std::cout<< "productA1 Disp"<<std::endl;
- }
- };
- class ProductA2: public AbstractProductA
- {
- private:
- /* data */
- public:
- ProductA2(){}
- ~ProductA2(){}
- void Show()
- {
- std::cout<< "productA2 show"<<std::endl;
- }
- void Disp()
- {
- std::cout<< "productA2 Disp"<<std::endl;
- }
- };
- class AbstractProductB
- {
- public:
- AbstractProductB() {}
- virtual ~AbstractProductB() {}
- virtual void Show() = 0;
- virtual void Disp() = 0;
- };
- class ProductB1 : public AbstractProductB
- {
- public:
- void Show()
- {
- std::cout<< "productB2 show"<<std::endl;
- }
- void Disp()
- {
- std::cout<< "productB2 Disp"<<std::endl;
- }
- };
- class Factory
- {
- public:
- virtual AbstractProductA *CreateProductA(void) = 0;
- virtual AbstractProductB *CreateProductB(void) = 0;
- };
- class Factory1 :Factory
- {
- public:
- AbstractProductA * CreateProductA(void)
- {
- return new ProductA1();
- }
- AbstractProductB * CreateProductB(void)
- {
- return new ProductB1();
- }
- };
- class Factory2:Factory
- {
- public:
- AbstractProductA * CreateProductA(void)
- {
- return new ProductA2();
- }
- AbstractProductB * CreateProductB(void)
- {
- return NULL;
- }
- };
- int main(int argc, char **argv)
- {
- Factory2 *new_factory2 = new Factory2();
- AbstractProductA *new_productA2 = new_factory2->CreateProductA();
- new_productA2->Show();
- Factory1 *new_factory1 = new Factory1();
- AbstractProductB *new_productB1 = new_factory1->CreateProductB();
- new_productB1->Show();
- }
- python 實現(xiàn)
python 實現(xiàn)
- #!/usr/bin/python3
- class AbstractProductA(object):
- def show(self):
- pass
- def disp(self):
- pass
- class ProductA1(AbstractProductA):
- def show(self):
- print("ProductA1 show")
- def disp(self):
- print("productA1 disp")
- class ProductA2(AbstractProductA):
- def show(self):
- print("ProductA2 show")
- def disp(self):
- print("productA2 disp")
- class AbstractProductB(object):
- def show(self):
- pass
- def disp(self):
- pass
- class ProductB1(AbstractProductB):
- def show(self):
- print("ProductB1 show")
- def disp(self):
- print("productB1 disp")
- class ProductB2(AbstractProductB):
- def show(self):
- print("ProductB2 show")
- def disp(self):
- print("productB2 disp")
- class Factory(object):
- def crete_product1(self):
- pass
- def crete_product2(self):
- pass
- class FactoryA(object):
- def crete_product1(self):
- return ProductA1()
- def crete_product2(self):
- return ProductA2()
- class FactoryB(object):
- def crete_product1(self):
- return ProductB1()
- def crete_product2(self):
- return ProductB2()
- if __name__ == "__main__":
- new_factory = FactoryA()
- new_product1 = new_factory.crete_product1()
- new_product1.show()
- new_product2 = new_factory.crete_product2()
- new_product2.disp()
抽象工廠模式優(yōu)缺點
- 1.你可以確保同一工廠生成的產(chǎn)品相互匹配??梢员苊饪蛻舳撕途唧w產(chǎn)品代碼的耦合。
- 2.單一職責(zé)原則。你可以將產(chǎn)品生成代碼抽取到同一位置, 使得代碼易于維護(hù)。
- 3.開閉原則。向應(yīng)用程序中引入新產(chǎn)品變體時, 你無需修改客戶端代碼。
- 4.由于采用該模式需要向應(yīng)用中引入眾多接口和類, 代碼可能會比之前更加復(fù)雜。
本文轉(zhuǎn)載自微信公眾號「羽林君」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系羽林君公眾號。