爲了理解和學習簡單工廠模式,咱們先看一段簡單計算器的代碼算法
class Program { static void Main(string[] args) { Console.Write("請輸入數字A:"); string A = Console.ReadLine(); Console.Write("請選擇運算符號(+、-、*、/):"); string B = Console.ReadLine(); Console.Write("請輸入數字B:"); string C = Console.ReadLine(); string D = ""; if (B == "+") D = Convert.ToString(Convert.ToDouble(A) + Convert.ToDouble(C)); if (B == "-") D = Convert.ToString(Convert.ToDouble(A) - Convert.ToDouble(C)); if (B == "*") D = Convert.ToString(Convert.ToDouble(A) * Convert.ToDouble(C)); if (B == "/") D = Convert.ToString(Convert.ToDouble(A) / Convert.ToDouble(C)); Console.WriteLine("結果是:" + D); Console.ReadKey(); } }
以上代碼存在幾點明顯問題ide
①A、B、C、D這樣的命名很是不規範,真實項目中應該避免使用學習
②if判斷分支,讓計算機多作了三次無用功優化
③除數的時候若是用戶輸入了非正數及符號,沒有相關處理。spa
根據上述三點問題進行優化後的代碼以下:code
class Program { static void Main(string[] args) { try { Console.Write("請輸入數字A:"); string strNumberA = Console.ReadLine(); Console.Write("請選擇運算符號(+、-、*、/):"); string strOperate = Console.ReadLine(); Console.Write("請輸入數字B:"); string strNumberB = Console.ReadLine(); string strResult = ""; switch (strOperate) { case "+": strResult = Convert.ToString(Convert.ToDouble(strNumberA) + Convert.ToDouble(strNumberB)); break; case "-": strResult = Convert.ToString(Convert.ToDouble(strNumberA) - Convert.ToDouble(strNumberB)); break; case "*": strResult = Convert.ToString(Convert.ToDouble(strNumberA) * Convert.ToDouble(strNumberB)); break; case "/": if (strNumberB != "0") strResult = Convert.ToString(Convert.ToDouble(strNumberA) / Convert.ToDouble(strNumberB)); else strResult = "除數不能爲0"; break; } Console.WriteLine("結果是:" + strResult); Console.ReadKey(); } catch (Exception ex) { Console.WriteLine("您的輸入有錯:" + ex.Message); } } }
就上述代碼而言,的確實現了簡單計算器的功能,可是咱們進一步思考這段代碼,若是此時 須要新作一個計算器呢?估計有不少小夥伴靈光一現,複製粘貼大法。咱們回想下古代活字印刷術的出現,對於印刷的巨大幫助。對象
⑴ 要改內容,只須要改動要改的文字,此爲可維護;blog
⑵這些字並不是用完此次就無用了,之後的印刷中能夠重複使用,此乃可複用;繼承
⑶若此版面內容要加字,只須要另刻字加入便可,這是可擴展。get
⑷字的排列多是豎排,多是橫排,此時只須要將活字移動就可作到知足排列需求,此是靈活性好。
而再活字印刷術出現以前,以上四點特性都沒法知足,要修改,必須重刻,要加字,必須重刻,要從新排列,必須重刻,印完這本後,此版已無任何可再利用價值。
★業務的封裝(讓業務邏輯與界面邏輯分開,下降耦合度)
根據上述思考,咱們將運算單獨封裝一個運算類 Operation
/// <summary> /// 運算類 /// </summary> public class Operaion { /// <summary> /// 計算方法 /// </summary> /// <param name="numberA">運算數</param> /// <param name="numberB">運算數</param> /// <param name="operate">符號</param> /// <returns>返回值</returns> public static double GetResult(double numberA, double numberB, string operate) { double result = 0d; switch (operate) { case "+": result = numberA + numberB; break; case "-": result = numberA - numberB; break; case "*": result = numberA * numberB; break; case "/": result = numberA / numberB; break; } return result; } }
客戶端調用的時候調用此方法便可:
class Program { static void Main(string[] args) { try { Console.Write("請輸入數字A:"); string strNumberA = Console.ReadLine(); Console.Write("請選擇運算符號(+、-、*、/):"); string strOperate = Console.ReadLine(); Console.Write("請輸入數字B:"); string strNumberB = Console.ReadLine(); string strResult = ""; //調用運算類中計算方法 strResult = Convert.ToString(Operaion.GetResult(Convert.ToDouble(strNumberA), Convert.ToDouble(strNumberB), strOperate)); Console.WriteLine("結果是:" + strResult); Console.ReadKey(); } catch (Exception ex) { Console.WriteLine("您的輸入有錯:" + ex.Message); } } }
上述代碼實現了業務邏輯與界面的分離,可是尚未真正運用到程序的精髓所在:封裝、繼承、多態,帶着思考和疑問,咱們作出進一步修改以下:
/// <summary> /// 運算類 /// </summary> public class Operaion { private double _numberA = 0; private double _numberB = 0; public double NumberA { get { return _numberA; } set { _numberA = value; } } public double NumberB { get { return _numberB; } set { _numberB = value; } } public virtual double GetResult() { double result = 0; return result; } } /// <summary> /// 加法類,繼承運算類 /// </summary> class OpertionAdd : Operaion { public override double GetResult() { double result = 0; result = NumberA + NumberB; return result; } } /// <summary> /// 減法類,繼承運算類 /// </summary> class OperationSub : Operaion { public override double GetResult() { double result = 0; result = NumberA - NumberB; return result; } } /// <summary> /// 乘法類,繼承運算類 /// </summary> class OperationMul : Operaion { public override double GetResult() { double result = 0; result = NumberA * NumberB; return result; } } /// <summary> ///除法類,繼承運算類 /// </summary> class OperationDiv : Operaion { public override double GetResult() { double result = 0; if (NumberB == 0) throw new Exception("除數不能爲0."); result = NumberA / NumberB; return result; } }
上述代碼寫完,此時就有一個疑問,如何讓計算器知道咱們但願用哪個算法呢?
下面咱們看看簡單運算工廠類
public class OperationFactory { public static Operaion createOperate(string operate) { Operaion oper = null; switch (operate) { case "+": oper = new OpertionAdd(); break; case "-": oper = new OperationSub(); break; case "*": oper = new OperationMul(); break; case "/": oper = new OperationDiv(); break; } return oper; } }
有了運算工廠類,咱們只須要輸入運算符號,工廠就能實例化適合的對象,經過多態,返回父類的方法實現了計算器的結果,客戶端代碼以下:
class Program { static void Main(string[] args) { try { Console.Write("請輸入數字A:"); string strNumberA = Console.ReadLine(); Console.Write("請選擇運算符號(+、-、*、/):"); string strOperate = Console.ReadLine(); Console.Write("請輸入數字B:"); string strNumberB = Console.ReadLine(); //調用工廠類進行計算 Operaion oper; oper = OperationFactory.createOperate(strOperate); oper.NumberA =double.Parse(strNumberA); oper.NumberB =double.Parse(strNumberB); //返回計算結果 var strResult = oper.GetResult(); Console.WriteLine("結果是:" + strResult); Console.ReadKey(); } catch (Exception ex) { Console.WriteLine("您的輸入有錯:" + ex.Message); } } }
這樣,無論咱們是控制檯程序、Windows程序,Web程序或者手機程序,均可以使用這段代碼來實現計算器的功能,若是有一天咱們須要更改加法運算,咱們改OperationAdd就能夠了,若是須要增長其餘複雜運算,好比平方根、立方根,咱們只須要增長相應的運算子類和運算類工廠,再switch中增長分支便可。