怎樣寫出高逼格的計算器(用上封裝、繼承、多態) -- 簡單工廠模式
1. 面向過程的計算器
static void Main(string[] args) { //面向過程的計算器 try { Console.WriteLine("請輸入數字A: "); string strNumA = Console.ReadLine(); Console.WriteLine("請選擇運算符號(+、-、*、/): "); string strOperate = Console.ReadLine(); Console.WriteLine("請輸入數字B: "); string strNumB = Console.ReadLine(); string strResult = string.Empty; switch (strOperate) { case "+": strResult = (Double.Parse(strNumA) + Double.Parse(strNumB)).ToString(); break; case "-": strResult = (Double.Parse(strNumA) - Double.Parse(strNumB)).ToString(); break; case "*": strResult = (Double.Parse(strNumA) * Double.Parse(strNumB)).ToString(); break; case "/": if (Double.Parse(strNumB) == 0) { throw new Exception("被除數不能為0!"); } strResult = (Double.Parse(strNumA) / Double.Parse(strNumB)).ToString(); break; default: throw new Exception("運算符輸入錯誤!"); } Console.WriteLine(strNumA + " " + strOperate + " " + strNumB + " = " + strResult); } catch (Exception ex) { Console.WriteLine("您輸入的有錯:" + ex.Message); } Console.ReadKey(); }
思考:
上面的計算器是Console版的,如果我要實現WinForm版、Web版、手機版。那怎麼辦呢?
Ctrl-C, Ctrl-V是一種方法(我剛寫代碼的時候就是這麼辦的)。但是當重覆的代碼多了,維護起來,可能就是一場災難。
這時面向對象的優勢就體現出來了,把計算器的功能封裝成一個計算器類,供Console, WinForm, Web等調用。將來要維護,只維護這一個類即可。
2. 面向對象1: 封裝 - 將計算和顯示分開
//業務的封裝 - 計算 public class Operation { public static double CalcResult(double numA, double numB, string op) { double result = 0d; switch (op) { case "+": result = numA + numB; break; case "-": result = numA - numB; break; case "*": result = numA * numB; break; case "/": if (numB == 0) { throw new Exception("被除數不能為0!"); } result = numA / numB; break; default: throw new Exception("運算符輸入錯誤!"); } return result; } } //客戶端代碼 - 界面 static void Main(string[] args) { try { Console.WriteLine("請輸入數字A: "); string strNumA = Console.ReadLine(); Console.WriteLine("請選擇運算符號(+、-、*、/): "); string strOperate = Console.ReadLine(); Console.WriteLine("請輸入數字B: "); string strNumB = Console.ReadLine(); string strResult = Operation.CalcResult(double.Parse(strNumA), double.Parse(strNumB), strOperate).ToString(); Console.WriteLine(strNumA + " " + strOperate + " " + strNumB + " = " + strResult); } catch (Exception ex) { Console.WriteLine("您輸入的有錯:" + ex.Message); } Console.ReadKey(); }
思考:
如果現在要加一個平方根運算,怎麼辦?看來只能改Operation類了,那麼已經寫好的加減乘除運算代碼是不是也會暴露出來,面臨著被誤修改的風險(如果這個類是計算工資的類,那風險得多大)。而且添加完平方根後,整個類都要重新編譯,豈不是很麻煩。
看來上面的實現擴展性和靈活性還是不夠好,需要再設計一下。
3. 面向對象2:封裝、繼承、多態 - 簡單工廠模式
/// <summary> /// 抽象類:運算類 /// </summary> public class Operation { private double _numA = 0; private double _numB = 0; public double NumA { get { return _numA; } set { _numA = value; } } public double NumB { get { return _numB; } set { _numB = value; } } public virtual double GetResult() { return 0; } } /// <summary> /// 加法 : 繼承運算類 /// </summary> public class OperationAdd : Operation { public override double GetResult() { return NumA + NumB; } } /// <summary> /// 減法 : 繼承運算類 /// </summary> public class OperationSub : Operation { public override double GetResult() { return NumA - NumB; } } /// <summary> /// 乘法 : 繼承運算類 /// </summary> public class OperationMul : Operation { public override double GetResult() { return NumA * NumB; } } /// <summary> /// 除法 : 繼承運算類 /// </summary> public class OperationDiv : Operation { public override double GetResult() { if (NumB == 0) throw new Exception("被除數不能為0"); else return NumA / NumB; } } /// <summary> /// 工廠 : 生產計算器 /// </summary> public class OperationFactory { public static Operation createOperation(string op) { Operation oper = null; switch (op) { case "+": oper = new OperationAdd(); break; case "-": oper = new OperationSub(); break; case "*": oper = new OperationMul(); break; case "/": oper = new OperationDiv(); break; default: throw new Exception("操作符錯誤,只支持+-*/四則運算。"); } return oper; } } /// <summary> /// 客戶端 /// </summary> /// <param name="args"></param> static void Main(string[] args) { try { Console.WriteLine("請輸入數字A: "); string strNumA = Console.ReadLine(); Console.WriteLine("請選擇運算符號(+、-、*、/): "); string strOperate = Console.ReadLine(); Console.WriteLine("請輸入數字B: "); string strNumB = Console.ReadLine(); Operation oper = OperationFactory.createOperation(strOperate); oper.NumA = double.Parse(strNumA); oper.NumB = double.Parse(strNumB); string strResult = oper.GetResult().ToString(); Console.WriteLine(strNumA + " " + strOperate + " " + strNumB + " = " + strResult); } catch (Exception ex) { Console.WriteLine("您輸入的有錯:" + ex.Message); } Console.ReadKey(); }
思考:
現在的計算器通過封裝、繼承、多態把程式的耦合度降低,更加的靈活,容易修改,易於服用。
4. 簡單工廠模式的UML類圖
----
參考文獻:《大話設計模式》 程傑 著