簡單工廠模式:
創建多種不同類型的產品,根據傳入參數的類型進行創建。
只有一個Creator方法,負責多種不同的產品的創建,傳入參數的類型來決定具體創建哪種產品,實現簡單,但是如果需要擴展產品的話,就需要修改Creator方法的實現。
有一個Pizza店,可以生產不同種類的Pizza,對於此代碼簡單如下:
//這是一個抽象的pizza,有很多不同種類的pizza,繼承於它。
[cpp]
class AbstractPizza
{
public:
AbstractPizza(void);
virtual ~AbstractPizza(void);
virtual void Taste() = 0;
int m_nPizzaType;
};
class AbstractPizza
{
public:
AbstractPizza(void);
virtual ~AbstractPizza(void);
virtual void Taste() = 0;
int m_nPizzaType;
};
//具體的pizza,繼承於抽象pizza。還有其他的多種不同類型的Pizza。
[cpp]
class SimplePizzaFactory
{
public:
enum PizzaType{
CheesePizzaTpe,
GreekPizzaType,
PipperPizzaType,
//..可以繼續後續添加
};
SimplePizzaFactory(void);
~SimplePizzaFactory(void);
AbstractPizza* CreatePizzaByType(PizzaType type){
switch (type)
{
case SimplePizzaFactory::CheesePizzaTpe:
{
return new CheesePizza;
//if you want, you can do additional initialization for new CheesePizza;
//like:
//AbstractPizza* pizza = new CheesePizza;
//assert(pizza);
//pizza->Initialize();
}
case SimplePizzaFactory::GreekPizzaType:
{
return new GreekPizza;
//if you want, you can do additional initialization for new CheesePizza;
}
case SimplePizzaFactory::PipperPizzaType:
{
return new PipperPizza;
//if you want, you can do additional initialization for new CheesePizza;
}
default:
break;
}
}
};
class SimplePizzaFactory
{
public:
enum PizzaType{
CheesePizzaTpe,
GreekPizzaType,
PipperPizzaType,
//..可以繼續後續添加
};
SimplePizzaFactory(void);
~SimplePizzaFactory(void);
AbstractPizza* CreatePizzaByType(PizzaType type){
switch (type)
{
case SimplePizzaFactory::CheesePizzaTpe:
{
return new CheesePizza;
//if you want, you can do additional initialization for new CheesePizza;
//like:
//AbstractPizza* pizza = new CheesePizza;
//assert(pizza);
//pizza->Initialize();
}
case SimplePizzaFactory::GreekPizzaType:
{
return new GreekPizza;
//if you want, you can do additional initialization for new CheesePizza;
}
case SimplePizzaFactory::PipperPizzaType:
{
return new PipperPizza;
//if you want, you can do additional initialization for new CheesePizza;
}
default:
break;
}
}
};
為了我們更好的管理Pizza的創建過程,一般我們會創建一個管理類,它負責創建不同種類的pizza產品。通過SimplePizzaFactory工廠的管理,我們通過傳入不同的類型就可以不同種類的pizza產品,外部的調用者只需要傳入類型,Creator方法就會返回正確的AbstractPizza的具體類型。甚至於你可以將SimplePizzaFactory定義為單例模式(如果工廠需要數據成員的話)便於以全局變量的方式使用。或者將CreatePizzaByType定義為靜態方法(如果沒有相關任何數據成員),這樣的話就不用創建任何工程對象,直接SimplePizzaFactory::CreatePizzaByType(nPizzaType)就可以,操作更簡答。它既然叫簡單工廠,確實足夠簡單,只有一個Creator方法(不過不能叫做工廠方法,注意沒有繼承),當有新的產品添加進來,必須需要修改Creator方法,以滿足新的產品創建的需要,不過說實話這種簡單工廠模式對於平常的很多程序都足夠。
[cpp]
class SimplePizzaFactory
{
public:
enum PizzaType{
CheesePizzaTpe,
GreekPizzaType,
PipperPizzaType,
//..可以繼續後續添加
};
SimplePizzaFactory(void);
~SimplePizzaFactory(void);
AbstractPizza* CreatePizzaByType(PizzaType type){
switch (type)
{
case SimplePizzaFactory::CheesePizzaTpe:
{
return new CheesePizza;
//if you want, you can do additional initialization for new CheesePizza;
//like:
//AbstractPizza* pizza = new CheesePizza;
//assert(pizza);
//pizza->Initialize();
}
case SimplePizzaFactory::GreekPizzaType:
{
return new GreekPizza;
//if you want, you can do additional initialization for new CheesePizza;
}
case SimplePizzaFactory::PipperPizzaType:
{
return new PipperPizza;
//if you want, you can do additional initialization for new CheesePizza;
}
default:
break;
}
}
};
class SimplePizzaFactory
{
public:
enum PizzaType{
CheesePizzaTpe,
GreekPizzaType,
PipperPizzaType,
//..可以繼續後續添加
};
SimplePizzaFactory(void);
~SimplePizzaFactory(void);
AbstractPizza* CreatePizzaByType(PizzaType type){
switch (type)
{
case SimplePizzaFactory::CheesePizzaTpe:
{
return new CheesePizza;
//if you want, you can do additional initialization for new CheesePizza;
//like:
//AbstractPizza* pizza = new CheesePizza;
//assert(pizza);
//pizza->Initialize();
}
case SimplePizzaFactory::GreekPizzaType:
{
return new GreekPizza;
//if you want, you can do additional initialization for new CheesePizza;
}
case SimplePizzaFactory::PipperPizzaType:
{
return new PipperPizza;
//if you want, you can do additional initialization for new CheesePizza;
}
default:
break;
}
}
};
工廠方法模式:
對擴展開放,對修改關閉,對於上面的簡單工廠,creator方法以後可能需要修改,因此我們可以通過將要改的方面單獨提煉出來。這就構造出了工廠方法模式。有一個抽象的工廠方法,它的出現將外部的調用統一化,由具體的工廠負責產品的創建過程。工廠方法模式就是將產品的創建過程延遲到子類,由子類負責具體的產品創建,而且一種工廠只生產一種產品。具體工廠和具體產品一一對應,抽象的Creator方法和抽象的產品對應。
這經常用在抽象類中,專為創建對象定義一個方法。子類就可以覆蓋這個方法來定義要創建的特定對象。通常與模板方法和並使用,模板方法在定義模板算法時一般需要先創建產品,然後再利用產品的方法創建一個流程。
一個抽象產品類,可以派生出多個具體產品類。
一個抽象工廠類,可以派生出多個具體工廠類。
每個具體工廠類只能創建一個具體產品類的實例。
還用上面的例子,現在首先需要一個抽象的Creator方法,你可以把它看成一個抽象工廠,其實也是它是一個特殊的抽象工廠,只生產一種產品.
不過下面的比普通的工廠方法模式又稍微高級了一點,它是參數化的工廠方法模式,靈活性更大。
[cpp]
class PizzaFactory
{
public:
enum PizzaType{
CheesePizzaTpe,
GreekPizzaType,
PipperPizzaType,
};
PizzaFactory(void);
~PizzaFactory(void);
AbstractPizza* PizzaFactory(PizzaType type)();
};
//具體的工廠,負責生產BeiJing的pizza。
class BeiJingPizzaFactory : public PizzaFactory
{
public:
BeiJingPizzaFactory(void);
~BeiJingPizzaFactory(void);
AbstractPizza* CreatePizzaByType(PizzaType type)(){
switch (type){
case PizzaFactory::CheesePizzaTpe:
return new BeiJingCheesePizza;
case PizzaFactory::GreekPizzaType:
return new BeiJingGreekPizza;
case PizzaFactory::PipperPizzaType:
return new BeiJingPipperPizza;
default:
return NULL;
};
}
};
class PizzaFactory
{
public:
enum PizzaType{
CheesePizzaTpe,
GreekPizzaType,
PipperPizzaType,
};
PizzaFactory(void);
~PizzaFactory(void);
AbstractPizza* PizzaFactory(PizzaType type)();
};
//具體的工廠,負責生產BeiJing的pizza。
class BeiJingPizzaFactory : public PizzaFactory
{
public:
BeiJingPizzaFactory(void);
~BeiJingPizzaFactory(void);
AbstractPizza* CreatePizzaByType(PizzaType type)(){
switch (type){
case PizzaFactory::CheesePizzaTpe:
return new BeiJingCheesePizza;
case PizzaFactory::GreekPizzaType:
return new BeiJingGreekPizza;
case PizzaFactory::PipperPizzaType:
return new BeiJingPipperPizza;
default:
return NULL;
};
}
};
關於BeiJingCheesePizza, BeiJingGreekPizza, BeiJingPipperPizza這些就不寫了,就是繼承於抽象的Pizza。
對擴展開放,對修改關閉:
如果再有天津的,河南的,意大利的等等Pizza。通過使用工廠方法模式,以後即使再有其他地區的pizza店,只需要添加另外的一個具體工廠和具體的產品就行了。不要糾結於增加新的PizzaType怎麼辦?工廠方法模式專注的點是有新地區的產品,而不是有新的PizzaType。因為最基本的工廠方法模式是一個工廠一個產品,一一對應。如果想著眼於type而忽略地區,可以考慮一種PizzaType一個Pizza工廠,那樣添加了新的type,就添加新的工廠和產品就可以了,完美符合對擴展開放,對修改關閉。
子類實例化:
工廠方法模式對外部提供的是一個工廠方法,它是一個抽象接口,這樣外部依賴的就是抽象而不是具體,減少代碼耦合性。將具體的new的操作放到子類工廠來實現。
應用:
說實話,找應用費了好久,畢竟整天Pizza,Pizza的很難給我們以啟發,僅僅是知道模式,而沒有看到它的巨大潛力和價值。
學習MFC的都知道Document和Application的關系。不同的Application對應不同的Document。app負責創建doc。app就是工廠,doc就是產品,一個工廠一個產品。
[cpp]
//App是工廠,它保存著創建的產品
//App
class Application
{
public:
void OpenDocument(){//模板方法
m_pDoc = CreateDocment();
m_pDoc->Open();
m_pDoc->Read();
}
void CloseDocument(){//模板方法
m_pDoc->Write();
m_pDoc->Close();
}
private:
virtual Document* CreateDocment() = 0;//工廠方法
private:
Document* m_pDoc;//這個
}
//抽象產品類,文檔可以打開關閉,讀寫。
class Document
{
public:
void Open();
void Close();
void Read();
void Write();
}
//App是工廠,它保存著創建的產品
//App
class Application
{
public:
void OpenDocument(){//模板方法
m_pDoc = CreateDocment();
m_pDoc->Open();
m_pDoc->Read();
}
void CloseDocument(){//模板方法
m_pDoc->Write();
m_pDoc->Close();
}
private:
virtual Document* CreateDocment() = 0;//工廠方法
private:
Document* m_pDoc;//這個
}
//抽象產品類,文檔可以打開關閉,讀寫。
class Document
{
public:
void Open();
void Close();
void Read();
void Write();
}
解釋:
上面兩個類一看到就會有種欣喜的感覺,將模板方法和工廠方法完美的組合了起來。工廠方法關心的是創建對象,由具體的工廠MyApp負責創建實現具體的產品MyDocument.同時,模板方法OpenDocument面向抽象的創建接口編程,負責定義了一套算法,子類繼承了Application,就繼承了一套算法,子類不用關心算法執行的步驟,子類只需要實現方法,父類負責調用子類的方法。
像經常看到的狀態機代碼,狀態機的跳轉流程是由預先定義的流程定義的,但是OnStateEnter和OnStateExit這樣的方法的實現是由具體應用定義的。父類負責調用子類OnStateEnter和OnStateExit方法的具體的實現,模板方法的典型應用。
抽象工廠:
抽象工廠關注的是創建一系列的產品,它是使用工廠方法實現的,不過是擁有多個工廠方法。
代碼就不寫了。
簡單工廠能把具體實現包裝起來,讓客戶端真正達到面向接口編程
工廠方法可以在高層進行編碼,讓服務端的產品線真正達到面向接口編程
抽象工廠能聚合整個產品簇,讓整個服務端的多個產品線真正達到面向接口編程
模板方法同樣是在高層進行編碼,也同樣是面向接口編程。
但工廠方法及抽象工廠方法著重抽象的是產品,而模板方法著重抽象的是步驟。
而我們通常會兩者一起結合起來使用。