簡單工廠模式學習
什麼是簡單工廠模式?
簡單工廠模式在實際項目中非常常見,是一種比較好的編程習慣。它的特點用一句話概括就是:
"當你需要什麼,只需要傳入一個正確的參數,就可以獲取你所需要的對象,創建細節無需知道。"
舉個例子:
如果一個軟件系統可以提供多個外觀不同的水果按鈕(如蘋果按鈕、橙子按鈕、香蕉按鈕),如下圖,這些按鈕都源自一個基類,只不過在繼承基類後不同的子類修改了部分屬性使得它們可以呈現不同的外觀。如果我們希望在使用這些按鈕時,不需要知道這些按鈕的名字,只需要知道表示該按鈕的參數,並提供一個調用方法,把參數傳入方法中就可以返回一個相對應的按鈕對象。 這就是一個簡單工廠模式。
簡單工廠模式,又稱靜態工廠方法,它可以根據參數不同來返回不同類的實例,通過專門定義一個類來負責創建其他實例,被創建的實例都有同樣的父類。
簡單工廠模式的三個角色:
- 工廠角色:負責實現創建所有具體產品的實例
- 抽象產品角色:所有具體產品角色的父類,實現描述所有實例的接口
- 具體產品角色:繼承自抽象產品角色,實現某個具體實例
參考:深入淺出設計模式——簡單工廠模式(Simple Factory).
簡單工廠模式實例解析
舉例場景:實現一個計算器,能根據你輸入的數字和運算符,輸出相應運算符下的計算結果。
抽象產品角色
#include <iostream>
#include <tr1/memory>
using namespace std;
class Operation
{
private:
double A, B;
public:
double GetA() const {return A;}
double GetB() const {return B;}
void SetA(double x) {A=x;}
void SetB(double y) {B=y;}
double virtual GetResult(){return 0;} //子類做各自實現
Operation():A(0), B(0){}
};
具體產品角色
class Add : public Operation
{
public:
double GetResult()
{
return GetA()+GetB();
}
};
class Sub : public Operation
{
public:
double GetResult()
{
return GetA()-GetB();
}
};
class Mul : public Operation
{
public:
double GetResult()
{
return GetA()*GetB();
}
};
class Div : public Operation
{
public:
double GetResult()
{
return GetA()/GetB();
}
};
工廠角色及調用
class SimpleFactory
{
public:
static Operation * CreateOpeartor(char ch)
{
Operation * p;
switch(ch)
{
case '+':
p = new Add();
break;
case '-':
p = new Sub();
break;
case '*':
p = new Mul();
break;
case '/':
p = new Div();
break;
}
return p;
}
};
int main(int argc, char *argv[])
{
double A = 0;
double B = 0;
char ch = '\0';
cin>>A>>ch>>B;
tr1::shared_ptr<Operation> op(SimpleFactory::CreateOpeartor(ch));
op->SetA(A);
op->SetB(B);
cout<<op->GetResult()<<endl;
}
模式優缺點
優點:
- 實現使用專門的工廠類用於創建對象,調用者無需創建使用對象,僅僅“消費”即可;
- 實現明確的責任分割。
缺點
- 簡單工廠模式最大的問題在於工廠角色的職責相對過重,增加新的實例需要修改工廠角色代碼的判斷邏輯,與開閉原則想違背;
- 工廠角色集中了大量創建邏輯,一定程度上增加了系統的複雜度,且一旦此模塊不能正常工作,會影響到整個系統;
簡單工廠模式最大的優點在於實現對象的創建和對象的使用分離,將對象的創建交給專門的工廠類負責,但是其最大的缺點在於工廠類不夠靈活,增加新的具體產品需要修改工廠類的判斷邏輯代碼,而且產品較多時,工廠方法代碼將會非常複雜。
簡單工廠的適用環境
- 工廠角色負責創建的對象比較少,不會造成工廠方法中的業務邏輯太過複雜;
- 調用者無需關心對象是如何創建的,無需知道類名,只需要知道類型對應的參數。