簡單工廠模式

模擬一個簡單的需求

設計一個簡單的計算器,可以完成加減乘除的操做,而且可以設置運算的兩個操做數(暫時不考慮計算器的界面)。ios

 

分析

思路1

能夠建立一個計算器類,裏面包含加減乘除的運算,以及設置獲取操做數等操做,客戶端直接建立一個計算器的對象,調用對應接口去執行運算。若是後續要添加新的運算,每次須要更改計算器類。c++

風險:因爲新增操做每次要更改原來設計的類,可能會因爲不當心改掉了原來的實現計算邏輯,從而致使原來正常運行的程序得不到正確的結果。設計模式

思路2

爲每種運算單獨設計一個類,客戶端使用的時候能夠根據不一樣的運算建立不一樣的對象,執行相應的操做。數組

因爲每種運算符都有相似的操做,只是最終對數據執行的運算不同,爲了不每一個運算類寫重複的代碼,能夠抽象出來一個運算類,包含公共的方法(設置操做數,獲取操做數,獲取計算結果等),具體運算類應該繼承這個基類,在每一個基類分別執行本身的運算。測試

此時,客戶端須要使用運算器的時候,建立對象使用new的時候仍是須要知道每一個運算類的類名,若這些類分別在不一樣的頭文件聲明,使用這些類的時候還須要include一堆的頭文件。若是要新增長運算符,上述的地方都要改動,很容易遺漏,很是的繁瑣。spa

解決方案:因爲建立的對象都是相似的對象(他們的父類都是同一個),能夠建立一個類,提供一個靜態方法,把建立具體類對象的工做都放到這個類中來完成,當客戶端須要使用運算器的時候,就只需跟這個建立類打交道,而且使用這些對象的時候直接經過運算類的基類引用或者指針來執行操做就好了。固然,客戶端和建立類須要使用一些通用的約定方式來表示要建立哪一種類型的運算實例。針對本需求,能夠直接使用加減乘數的字符來進行約定(「+」,「-」,「*」,「/」)。經過這個修改以後,就可以下降客戶與每種運算類的耦合度。若是後續須要增長新的運算類,也不須要更改原來已經實現無缺的各個具體的運算類,也就不會致使原來正常運行的結果因爲不當心修改了原有代碼致使結果不正確。設計

而上述所說的爲了建立具體運算對象和增長的類,就是一個工廠類,解決方案就是簡單工廠模式。指針

 

總結

簡單工廠模式並不屬於23種GOF設計模式之一。code

簡單工廠模式違背了面向對象設計中的開放封閉原則(簡而言之,就是對擴展開放,對修改封閉)。按照上述的需求,須要增長一種運算,不妨就假設增長指數運算。此時須要增長一個指數運算類(這種是擴展操做,不修改原有實現,只要新增一個類,就是對擴展開放),還須要在工廠類中增長一種對象的建立邏輯(這種是修改操做,面向對象不提倡修改,就是對修改封閉),這樣的修改仍是會致使風險。對象

 

c++示例代碼

頭文件calculator.h,聲明瞭抽象類運算類,以及具體的運算類,還有運算器工廠類

 1 #ifndef __CALCULATOR_H__
 2 #define __CALCULATOR_H__
 3 
 4 //運算抽象類
 5 class MyOperator
 6 {
 7 public:
 8     MyOperator(char op, double A = 0.0, double B = 0.0) :m_op(op), m_numberA(A), m_numberB(B) {}
 9     virtual ~MyOperator() {}
10 
11     //獲取運算結果
12     virtual double getResult()=0;
13     //獲取操做數
14     double getNumA()const { return m_numberA; }
15     double getNumB()const { return m_numberB; }
16     //獲取運算符
17     char getOp()const { return m_op; }
18     //設置操做數
19     void setNumA(double A) { m_numberA = A; }
20     void setNumB(double B) { m_numberB = B; }
21 
22 private:
23     //運算符
24     char m_op;
25     //運算的兩個操做數
26     double m_numberA;
27     double m_numberB;
28 };
29 
30 //加法運算類:繼承運算抽象類
31 class OperatorPlus:public MyOperator
32 {
33 public:
34     OperatorPlus(char op,double A = 0.0,double B = 0.0):MyOperator(op,A,B) {}
35     virtual double getResult();
36 };
37 
38 //減法運算類:繼承運算抽象類
39 class OperatorMinus :public MyOperator
40 {
41 public:
42     OperatorMinus(char op,double A = 0.0, double B = 0.0) :MyOperator(op,A, B) {}
43     virtual double getResult();
44 };
45 
46 //乘法運算類:繼承運算抽象類
47 class OperatorMultiply :public MyOperator
48 {
49 public:
50     OperatorMultiply(char op,double A = 0.0, double B = 0.0) :MyOperator(op,A, B) {}
51     virtual double getResult();
52 };
53 
54 //除法運算類:繼承運算抽象類
55 class OperatorDivision :public MyOperator
56 {
57 public:
58     OperatorDivision(char op,double A = 0.0, double B = 0.0) :MyOperator(op,A, B) {}
59     virtual double getResult();
60 };
61 
62 //運算工廠類,用於生產客戶端須要的具體類
63 class OperatorFactory
64 {
65 public:
66     static MyOperator* getOperator(char op,double A = 0.0,double B = 0.0);
67 };
68 #endif

實現文件calculator.cpp,生面聲明的每一個類的具體實現

 1 #include <iostream>
 2 #include "calculator.h"
 3 
 4 using namespace std;
 5 
 6 //加法運算
 7 double OperatorPlus::getResult()
 8 {
 9     return (getNumA() + getNumB());
10 }
11 
12 //減法運算
13 double OperatorMinus::getResult()
14 {
15     return (getNumA()-getNumB());
16 }
17 
18 //乘法運算
19 double OperatorMultiply::getResult()
20 {
21     return (getNumA() * getNumB());
22 }
23 
24 //除法運算
25 double OperatorDivision::getResult()
26 {
27     double result = 0.0;
28     if (0 == getNumB())
29     {
30         cout << "B not allow to be 0" << endl;
31     }
32     else
33     {
34         result = getNumA() / getNumB();
35     }
36     return result;
37 }
38 
39 //運算工廠類,用於生產客戶端須要的具體運算類
40 MyOperator* OperatorFactory::getOperator(char opStr,double A,double B)
41 {
42     switch (opStr)
43     {
44     case '+':
45         return new OperatorPlus(opStr, A, B);
46     case '-':
47         return new OperatorMinus(opStr, A, B);
48     case '*':
49         return new OperatorMultiply(opStr, A, B);
50     case '/':
51         return new OperatorDivision(opStr, A, B);
52     default:
53         cout << "NOT FOUND OPERATOR" << endl;
54         return nullptr;
55     }
56 }

測試文件testCalculator.cpp,調用運算器類的客戶端

 1 #include "calculator.h"
 2 #include <iostream>
 3 
 4 using namespace std;
 5 
 6 int main()
 7 {
 8     //聲明一個指針數組,用於保存運算類對象
 9     MyOperator* myOp[4];
10 
11     //獲取一個加法類的對象
12     myOp[0] = OperatorFactory::getOperator('+', 1.0, 2.0);
13     //獲取一個減法類的對象
14     myOp[1] = OperatorFactory::getOperator('-', 1.0, 2.0);
15     //獲取一個乘法類的對象
16     myOp[2] = OperatorFactory::getOperator('*', 1.0, 2.0);
17     //獲取一個除法類的對象
18     myOp[3] = OperatorFactory::getOperator('/', 1.0, 2.0);
19 
20     //多態的運用,用基類指針指向每一個子類的對象,而且獲取計算結果getResult()
21     MyOperator *p = myOp[0];
22     for (int i = 0; i < 4; p = myOp[++i])
23     {
24         cout << p->getNumA() << p->getOp() << p->getNumB() << "=" << p->getResult() << endl;
25         //用完就清理現場
26         delete p;
27         p = nullptr;
28     }
29     return 0;
30 }

運行結果

相關文章
相關標籤/搜索