設計模式之簡單工廠模式、工廠模式、抽象工廠模式的對比
前言:
設計模式已經經歷了很長一段時間的發展,它們提供了軟件開發過程中面臨的一般問題的最佳解決方案。學習這些模式有助于經驗不足的開發人員通過一種簡單快捷的方式來學習軟件設計。
一般我們會說設計模式一共有23種,總體來說設計模式分為三大類:
創建型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。
結構型模式,共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
行為型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。
今天主要是分析 簡單工廠模式、工廠模式和抽象工廠模式的區別,所以這里就簡單介紹一下設計模式的概念。
網上的很多資料都是在闡述著:工廠模式的好處就是解耦。相信大家對解耦這個詞也不陌生,那解耦究竟有什么好處呢?
- 1.為了提高內聚(Cohesion)和松耦合(Coupling),我們經常會抽象出一些類的公共接口以形成抽象基類或者接口。這樣我們可以通過聲明一個指向基類的指針來指向實際的子類實現,達到了多態的目的。這里很容易出現的一個問題 n 多的子類繼承自抽象基類,我們不得不在每次要用到子類的地方就編寫諸如 new ×××;的代碼。這里帶來兩個問題:
客戶程序員必須知道實際子類的名稱(當系統復雜后,命名將是一個很不好處理的問題,為了處理可能的名字沖突,有的命名可能并不是具有很好的可讀性和可記憶性,就姑且不論不同程序員千奇百怪的個人偏好了)。程序的擴展性和維護變得越來越困難。
- 2.還有一種情況就是在父類中并不知道具體要實例化哪一個具體的子類。這里的意思為:假設我們在類 A 中要使用到類 B,B 是一個抽象父類,在 A 中并不知道具體要實例化那一個 B 的子類,但是在類 A 的子類 D 中是可以知道的。在 A 中我們沒有辦法直接使用類似于 new ×××的語句,因為根本就不知道×××是什么。
以上兩個問題也就引出了工廠模式的兩個最重要的功能:定義創建對象的接口,封裝了對象的創建;使得具體化類的工作延遲到了子類中。
對于工廠模式,為了使其能更好的解決多種情況的問題,將其分為三類:簡單工廠模式(Simple Factory),工廠方法模式(Factory Method),抽象工廠模式(Abstract Factory)。GOAT 經常使用會遇到一些設計模式的使用,但是很少去細究里面的區別,這把就讓我來大家分享一下,我認知中的這三種工廠模式。
簡單工廠模式
我們把被創建的對象稱為“產品”,把創建產品的對象稱為“工廠”。如果要創建的產品不多,只要一個工廠類就可以完成,這種模式叫“簡單工廠模式”。
結構定義:
是由一個工廠對象決定創建出哪一種產品類的實例。簡單工廠模式中包含的角色及其相應的職責如下:
工廠角色(Creator):這是簡單工廠模式的核心,由它負責創建所有的類的內部邏輯。當然工廠類必須能夠被外界調用,創建所需要的產品對象。
抽象(Product)產品角色:簡單工廠模式所創建的所有對象的父類,注意,這里的父類可以是接口也可以是抽象類,它負責描述所有實例所共有的公共接口。
具體產品(Concrete Product)角色:簡單工廠所創建的具體實例對象,這些具體的產品往往都擁有共同的父類。
定義一個創建產品對象的工廠接口,將產品對象的實際創建工作推遲到具體子工廠類當中。這滿足創建型模式中所要求的“創建與使用相分離”的特點。
結構圖如下
范例如下:
C++實現
- #include <iostream>
- using namespace std;
- enum Product_Type
- {
- Product1_,
- Product2_,
- };
- class AbstractProduct //抽象(Product)產品角色
- {
- public:
- AbstractProduct() {}
- virtual ~AbstractProduct() {}
- virtual void Show() = 0;
- };
- class Product1 : public AbstractProduct //具體產品(Concrete Product)角色
- {
- private:
- /* data */
- public:
- Product1(/* args */);
- ~Product1();
- void Show()
- {
- std::cout<< "product1"<<std::endl;
- }
- };
- Product1::Product1()
- {
- }
- Product1::~Product1()
- {
- }
- class Product2 : public AbstractProduct //具體產品(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實現
- #!/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()
我們只需要調用不同的成員函數,工廠就幫我們實例化出想要的對象,利用上轉型對象,返回父類的方式實現了結果。可以發現簡單工廠模式代碼簡單,但不符合OCP(面向對象設計的基本原則之一 OCP(開閉原則):一個軟件的實體應當對擴展開放,對修改關閉)。
總結 :
1、簡單工廠模式最大的優點在于工廠類中可以判斷客戶的的選擇來動態實例化相關的類,對于客戶端來說,去除了具體產品的依賴。
2、缺點就是:很明顯工廠類集中了對所有實例創建的邏輯,如果我們要新增子類或者改變方法的話,就得每次都修改工廠類里面的代碼,工廠類中的代碼就會十分臃腫,這就等于說我們不進開放了擴展,還開放了修改,這樣就違反了開放-封閉原則。
你可能在不知不覺中已經用到過這種模式了,但簡單工廠模式并不屬于23種設計模式之一,下面介紹他的改進版本:工廠方法模式。
工廠模式
工廠方法模式是一種創建型設計模式, 其在父類中提供一個創建對象的方法, 允許子類決定實例化對象的類型。
工廠方法模式的結構組成:
抽象工廠類廠(AbstractFactory):工廠方法模式的核心類,提供創建具體產品的接口,由具體工廠類實現。
具體工廠類(Producer):繼承于抽象工廠,實現創建對應具體產品對象的方式。
抽象產品類(Factory):它是具體產品繼承的父類(基類)。
具體產品類(Factory1):具體工廠所創建的對象,就是此類。
C++實現
- #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實現
- #!/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()
工廠方法模式優缺點
- 1.你可以避免創建者和具體產品之間的緊密耦合。
- 2.單一職責原則。你可以將產品創建代碼放在程序的單一位置, 從而使得代碼更容易維護。
- 3.開閉原則。無需更改現有客戶端代碼, 你就可以在程序中引入新的產品類型。
- 4.應用工廠方法模式需要引入許多新的子類, 代碼可能會因此變得更復雜。最好的情況是將該模式引入創建者類的現有層次結構中。
抽象工廠模式
抽象工廠模式是一種創建型設計模式, 它能創建一系列相關的對象, 而無需指定其具體類。是更多一重的工廠模式中。
結構定義(類似工廠模式):
抽象工廠類廠(AbstractFactory):工廠方法模式的核心類,提供創建具體產品的接口,由具體工廠類實現。
具體工廠類(Producer):繼承于抽象工廠,實現創建對應具體產品對象的方式。
抽象產品類(Factory):它是具體產品繼承的父類(基類)。
具體產品類(Factory1):具體工廠所創建的對象,就是此類。
結構圖如下
C++實現
- #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 實現
python 實現
- #!/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()
抽象工廠模式優缺點
- 1.你可以確保同一工廠生成的產品相互匹配。可以避免客戶端和具體產品代碼的耦合。
- 2.單一職責原則。你可以將產品生成代碼抽取到同一位置, 使得代碼易于維護。
- 3.開閉原則。向應用程序中引入新產品變體時, 你無需修改客戶端代碼。
- 4.由于采用該模式需要向應用中引入眾多接口和類, 代碼可能會比之前更加復雜。
本文轉載自微信公眾號「羽林君」,可以通過以下二維碼關注。轉載本文請聯系羽林君公眾號。