1. 程式人生 > >三種工廠模式的C++實現

三種工廠模式的C++實現

引出工廠模式的設計問題

◆ 1.為了提高內聚(Cohesion)和鬆耦合(Coupling),我們經常會抽象出一些類的公共介面以形成抽象基類或者介面。這樣我們可以通過宣告一個指向基類的指標來指向實際的子類實現,達到了多型的目的。這裡很容易出現的一個問題 n 多的子類繼承自抽象基類,我們不得不在每次要用到子類的地方就編寫諸如 new ×××;的程式碼。這裡帶來兩個問題:
客戶程式設計師必須知道實際子類的名稱(當系統複雜後,命名將是一個很不好處理的問題,為了處理可能的名字衝突,有的命名可能並不是具有很好的可讀性和可記憶性,就姑且不論不同程式設計師千奇百怪的個人偏好了)。
程式的擴充套件性和維護變得越來越困難。
◆ 2.還有一種情況就是在父類中並不知道具體要例項化哪一個具體的子類。這裡的意思為:假設我們在類 A 中要使用到類 B,B 是一個抽象父類,在 A 中並不知道具體要例項化那一個 B 的子類,但是在類 A 的子類 D 中是可以知道的。在 A 中我們沒有辦法直接使用類似於 new ×××的語句,因為根本就不知道×××是什麼。

以上兩個問題也就引出了工廠模式的兩個最重要的功能:
定義建立物件的介面,封裝了物件的建立;
使得具體化類的工作延遲到了子類中。

對於工廠模式,為了使其能更好的解決多種情況的問題,將其分為三類:簡單工廠模式(Simple Factory),工廠方法模式(Factory Method),抽象工廠模式(Abstract Factory)。下面來一一搞定。

簡單工廠

        具體情形:有一個肥皂廠,生產各種肥皂,有舒膚佳,夏士蓮,娜愛斯等。給這個肥皂廠建模。

        UML圖如下:


對於簡單設計模式的結構圖,我們可以很清晰的看到它的組成:
1) 工廠類角色:這是本模式的核心,含有一定的商業邏輯和判斷邏輯。
2) 抽象產品角色:它一般是具體產品繼承的父類或者實現的介面。
3) 具體產品角色:工廠類所建立的物件就是此角色的例項。
簡單設計模式存在的目的很簡單:定義一個用於建立物件的介面。

缺點:對修改不封閉,新增加產品您要修改工廠。違法了鼎鼎大名的開閉法則(OCP)。

程式碼實現:

#include <iostream>
using namespace std;
enum PRODUCTTYPE {SFJ,XSL,NAS};
class soapBase
{
	public:
	virtual ~soapBase(){};
	virtual void show() = 0;
};

class SFJSoap:public soapBase
{
	public:
	void show() {cout<<"SFJ Soap!"<<endl;}
};

class XSLSoap:public soapBase
{
	public:
	void show() {cout<<"XSL Soap!"<<endl;}
};

class NASSoap:public soapBase
{
	public:
	void show() {cout<<"NAS Soap!"<<endl;}
};

class Factory
{
	public:
	soapBase * creatSoap(PRODUCTTYPE type)
	{
		switch(type)
		{
			case SFJ: 
				return new SFJSoap();
				break;
			case XSL:
				return new XSLSoap();
				break;
			case NAS:
				return new NASSoap();
				break;
			default:break;
		}
		
	}
};

int main()
{
	Factory factory;
	soapBase* pSoap1 = factory.creatSoap(SFJ);
	pSoap1->show();
	soapBase* pSoap2 = factory.creatSoap(XSL);
	pSoap2->show();
	soapBase* pSoap3 = factory.creatSoap(NAS);
	pSoap3->show();
	delete pSoap1;
	delete pSoap2;
	delete pSoap3;
	return 0;
}


執行結果


工廠方法模式

具體情形:最近莫名肥皂需求激增!! 於是要獨立每個生產線,每個生產線只生產一種肥皂。

UML圖如下:


        其實這才是真正的工廠模式,簡單工廠模式只能算是“坑爹版”的工廠模式。我們能很容易看出工廠方法模式和簡單工廠模式的區別之處。工廠方法模式的應用並不是只是為了封裝物件的建立,而是要把物件的建立放到子類中實現:Factory中只是提供了物件建立的介面,其實現將放在Factory的子類ConcreteFactory中進行。
對於工廠方法模式的組成:
1)抽象工廠角色: 這是工廠方法模式的核心,它與應用程式無關。是具體工廠角色必須實現的介面或者必須繼承的父類。
2)具體工廠角色:它含有和具體業務邏輯有關的程式碼。由應用程式呼叫以建立對應的具體產品的物件。
3)抽象產品角色:它是具體產品繼承的父類或者是實現的介面。
4)具體產品角色:具體工廠角色所建立的物件就是此角色的例項。

缺點:每增加一種產品,就需要增加一個物件的工廠。如果這家公司發展迅速,推出了很多新的處理器核,那麼就要開設相應的新工廠。在C++實現中,就是要定義一個個的工廠類。顯然,相比簡單工廠模式,工廠方法模式需要更多的類定義。

程式碼實現:

#include <iostream>
using namespace std;
enum SOAPTYPE {SFJ,XSL,NAS};

class soapBase
{
	public:
	virtual ~soapBase(){};
	virtual void show() = 0;
};

class SFJSoap:public soapBase
{
	public:
	void show() {cout<<"SFJ Soap!"<<endl;}
};

class XSLSoap:public soapBase
{
	public:
	void show() {cout<<"XSL Soap!"<<endl;}
};

class NASSoap:public soapBase
{
	public:
	void show() {cout<<"NAS Soap!"<<endl;}
};

class FactoryBase
{
	public:
	virtual soapBase * creatSoap() = 0;
};

class SFJFactory:public FactoryBase
{
	public:
	soapBase * creatSoap()
	{
		return new SFJSoap();
	}
};

class XSLFactory:public FactoryBase
{
	public:
	soapBase * creatSoap()
	{
		return new XSLSoap();
	}
};

class NASFactory:public FactoryBase
{
	public:
	soapBase * creatSoap()
	{
		return new NASSoap();
	}
};



int main()
{
	SFJFactory factory1;
	soapBase* pSoap1 = factory1.creatSoap();
	pSoap1->show();
	XSLFactory factory2;
	soapBase* pSoap2 = factory2.creatSoap();
	pSoap2->show();
	NASFactory factory3;
	soapBase* pSoap3 = factory3.creatSoap();
	pSoap3->show();
	delete pSoap1;
	delete pSoap2;
	delete pSoap3;
	return 0;
}

執行結果


抽象工廠模式

具體情形:這個肥皂廠發現搞牙膏也很賺錢,決定做牙膏。牙膏有高檔低檔,肥皂也是。現在搞兩個廠房,一個生產低檔的牙膏和肥皂,一個生產高檔的牙膏和肥皂。

比如,廠房一生產中華牙膏、娜愛斯肥皂,廠房二生產黑人牙膏和舒膚佳牙膏

 UML圖如下:


對於上面的結構圖,可以看出抽象工廠模式,比前兩者更為的複雜和一般性,抽象工廠模式和工廠方法模式的區別就在於需要建立物件的複雜程度上。
抽象工廠模式:給客戶端提供一個介面,可以建立多個產品族中的產品物件 ,而且使用抽象工廠模式還要滿足一下條件:
1)系統中有多個產品族,而系統一次只可能消費其中一族產品。
2)同屬於同一個產品族的產品以其使用。

抽象工廠模式的組成(和工廠方法模式一樣):
1)抽象工廠角色:這是工廠方法模式的核心,它與應用程式無關。是具體工廠角色必須實現的介面或者必須繼承的父類。
2)具體工廠角色:它含有和具體業務邏輯有關的程式碼。由應用程式呼叫以建立對應的具體產品的物件。
3)抽象產品角色:它是具體產品繼承的父類或者是實現的介面。
4)具體產品角色:具體工廠角色所建立的物件就是此角色的例項。

程式碼實現

#include <iostream>
using namespace std;
enum SOAPTYPE {SFJ,XSL,NAS};
enum TOOTHTYPE {HR,ZH};

class SoapBase
{
	public:
	virtual ~SoapBase(){};
	virtual void show() = 0;
};

class SFJSoap:public SoapBase
{
	public:
	void show() {cout<<"SFJ Soap!"<<endl;}
};

class NASSoap:public SoapBase
{
	public:
	void show() {cout<<"NAS Soap!"<<endl;}
};

class ToothBase
{
	public:
	virtual ~ToothBase(){};
	virtual void show() = 0;
};

class HRTooth:public ToothBase
{
	public:
	void show() {cout<<"Hei ren Toothpaste!"<<endl;}
};

class ChinaTooth:public ToothBase
{
	public:
	void show() {cout<<"China Toothpaste!"<<endl;}
};

class FactoryBase
{
	public:
	virtual SoapBase * creatSoap() = 0;
	virtual ToothBase * creatToothpaste() = 0;
};

class FactoryA :public FactoryBase
{
	public:
	SoapBase * creatSoap()
	{
		return new SFJSoap();
	}
	
	ToothBase * creatToothpaste()
	{
		return new HRTooth();
	}
};

class FactoryB :public FactoryBase
{
	public:
	SoapBase * creatSoap()
	{
		return new NASSoap();
	}
	
	ToothBase * creatToothpaste()
	{
		return new ChinaTooth();
	}
};


int main()
{
	FactoryA factory1;
	FactoryB factory2;
	SoapBase *pSoap1 = NULL;
	ToothBase *pToothpaste1 = NULL;
	pSoap1 = factory1.creatSoap();
	pToothpaste1 = factory1.creatToothpaste();
	pSoap1->show();
	pToothpaste1->show();
	
	SoapBase *pSoap2 = NULL;
	ToothBase *pToothpaste2 = NULL;
	pSoap2 = factory2.creatSoap();
	pToothpaste2 = factory2.creatToothpaste();
	pSoap2->show();
	pToothpaste2->show();
	
	delete pSoap1;
	delete pSoap2;
	delete pToothpaste1;
	delete pToothpaste2;
	
	return 0;
}

執行結果


參考

C++設計模式 http://www.weixueyuan.net/cpp/shejimoshi/

設計模式C++實現(1)——工廠模式 - http://blog.csdn.net/wuzhekai1985/article/details/6660462