第4章 建立型模式—工廠方法模式(1)
1. 簡單工廠
1.1 簡單工廠的定義
(1)提供一個建立物件例項的功能,而無須關心其具體實現。
①Api介面:定義客戶所需要的功能介面
②Impl:具體實現Api的實現類,可能會有多個
③SimpleFatory類:工廠,選擇合適的實現類來建立Api介面物件
④Client:客戶端,通過Factory來獲取Api介面物件,然後面向Api介面程式設計。
(2)思考簡單工廠
①簡單工廠的本質:選擇實現,其重點在選擇。工廠類內部的主要功能是“選擇合適的實現類”來建立例項物件。
②簡單工廠的目的:為客戶端選擇相應的實現,從而使得客戶端和實現之間解耦
(3)簡單工廠命名的建議
①類名建議為“模組名稱+Factory”。比如,使用者模組的工廠就為UserFactory
②方法名通常為“get+介面名稱”或者是“create+介面名稱”。比如有一個介面名稱為UserEbi,那麼方法名稱通常為getUserEbi或createUserEbi。
③不提倡將方法名稱命名為“new+介面名稱”,應該new在C++中是關鍵字,而且通過簡單工廠獲取的物件例項,並不一定每次都是要new一個新的例項。如果使用newUserEbi,會讓人錯覺,好象每次都是new一個新的例項一樣。
1.2 簡單工廠的優缺點
(1)簡單工廠的優點
①幫助封裝:簡單工廠雖然簡單,但是非常友好地幫助我們實現了元件的封裝,讓元件外部能真正的面向介面程式設計
②解耦,通過簡單工廠,實現了客戶端和具體實現類的解耦,客戶端根本不知道具體是由誰來實現的,也不知道具體如何實現,只是通過工廠獲取它需要的介面物件。
(2)簡單工廠的缺點
①可能增加客戶端的複雜度,客戶端通過引數來選擇具體的實現類,那麼就必須讓客戶端了解各個引數所代表的具體功能和含義,會增加使用難度,也部分暴露了其內部實現。
②不方便擴充套件子工廠,將工廠類的建構函式設有私有,使用靜態方法也建立介面。所以也就不能通過寫簡單工廠類的子類來改變建立介面方法的行為了。不過,通常情況下是不需要為簡單工廠建立子類的。
③當新增加介面的實現類時,須去修改工廠類的程式碼,這不符合開閉原則。
④所有產品都是由一個工廠建立,工廠類的職責較重,業務邏輯較為複雜,具體產品與工廠類之間的耦合度高,嚴重地影響了系統的靈活性和擴充套件性。
1.3 何時選用簡單工廠
①如果要完全封裝隔離具體實現,讓外部只能通過介面來操作封裝體。可以選用簡單工廠,讓客戶端通過工廠來獲取相應的介面,而無須關心具體的實現
②如果想把建立物件的職責集中管理控制,可以選用簡單工廠
【例項分析】利用簡單工廠實現的計算器
//建立型模式:簡單工廠
#include <stdio.h>
//運算類(其它的加減乘法類從這裡繼承)
class COperator
{
protected:
double mFirst;
double mSecond;
public:
void setFirst(double value){mFirst = value;}
double getFirst(){return mFirst;}
void setSecond(double value){mSecond = value;}
double getSecond(){return mSecond;}
virtual double getResult(){return 0;}
};
//加法類
class CAdd : public COperator
{
public:
double getResult()
{
return mFirst + mSecond;
}
};
//減法類
class CSub : public COperator
{
public:
double getResult()
{
return mFirst - mSecond;
}
};
//乘法類
class CMul : public COperator
{
public:
double getResult()
{
return mFirst * mSecond;
}
};
//除法類
class CDiv : public COperator
{
public:
double getResult()
{
const double P = 0.000000000000001;
if((-P < mSecond) && (mSecond< P)) //除數不能為0
{
return 0;
}
return mFirst / mSecond;
}
};
//簡單工廠類
class CSimpleFactory
{
public:
/**
*建立具體運算實現類物件的方法
*@引數:從外部傳入的選擇條件(+、-、*、/)
*@返回值:建立好的運算實現類物件
*/
//將建立函式定義為靜態成員函式,可以讓客戶端省去建立工廠類物件
static COperator* createOperator(char cOperator)
{
COperator* oper = NULL;
switch(cOperator) //根據客戶端傳入的引數,選擇建立具體的類
{
case '+':
oper = new CAdd();
break;
case '-':
oper = new CSub();
break;
case '*':
oper = new CMul();
break;
case '/':
oper = new CDiv();
break;
}
return oper;
}
};
int main()
{
//客戶端呼叫例子
//客戶端只需依賴COperator的介面類和工廠類,而無法知道具體的實現類
//實現了客戶端和具體實現類之間的解耦
COperator* oper = CSimpleFactory::createOperator('/');
oper->setFirst(1);
oper->setSecond(2);
printf("%f + %f = %f\n", oper->getFirst(),oper->getSecond(),oper->getResult());
return 0;
}