前言:
設計模式已經經歷了很長一段時間的發展,它們提供了軟體開發過程中面臨的一般問題的最佳解決方案。學習這些模式有助於經驗不足的開發人員通過一種簡單快捷的方式來學習軟體設計。
一般我們會說設計模式一共有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 實現
#!/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.由於採用該模式需要嚮應用中引入眾多介面和類, 程式碼可能會比之前更加複雜。
結語
這就是我分享的簡單工廠模式、工廠模式和抽象工廠模式的區別,如果大家有更好的想法和需求,也歡迎大家加我好友交流分享哈。
—END—
推薦閱讀
【3】CPU中的程式是怎麼執行起來的 必讀
【5】階段性文章總結分析
本公眾號全部原創乾貨已整理成一個目錄,回覆[ 資源 ]即可獲得。