读《大话设计模式》——《业务封装,工厂模式》
一、面试受挫——代码无错就是好?
面试题目:“请用C++,Java,C#或VB.NET任意一种面向对象语言实现一个计算器控制台程序,要求输入两个数和运算符号,得到结果。”
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); } }
上述代码,且先不说出题人的意思,单就上面的代码,就有很多不足的地方需要改进。比如变量命名,命名为ABCD,变量不带有任何具体含义,这是非常不规范的;判断分支,上面的写法,意味着每个条件都要做判断,等于计算机做了三次无用功;数据输入有效性判断等,如果用户输入的是字符符号而不是数字怎么办?如果除数时,客户输入了0怎么办?这些都是可以改进的地方。
经过第一交改进后
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 != "") strResult = Convert.ToString(Convert.ToDouble(strNumberA) / Convert.ToDouble(strNumberB)); else strResult = "除数不能为0"; break; } Console.WriteLine("结果是:" + strResult); Console.ReadLine(); } catch (Exception ex) { Console.WriteLine("您的输入有错:" + ex.Message); } } }
但是仍旧没有用到面向对象,有人说初级程序员的工作就是 Ctrl+C 和 Ctrl+V,这其实是非常不好的编码习惯,因为当你的代码中重复的代码多到一定程度,维护的时候,可能就是一场灾难。越大的系统,这种方式带来的问题越严重,编程有一原则,就是用尽可能的办法去避免重复。
二、业务的封装
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 = Convert.ToString(Operation.GetResult(Convert.ToDouble(strNumberA),Convert.ToDouble(strNumberB), strOperate)); Console.WriteLine("结果是:" + strResult); Console.ReadLine(); } catch (Exception ex) { Console.WriteLine("您的输入有错:" + ex.Message); } } } public class Operation { 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; } }
现在是Windows程序,Web版程序需要运算可以用它,PDA,手机等需要移动系统的软件需要运算也可以用它(利用这个运算类Operation)。
三、工厂模式
如果现在公司要求你为公司的薪资管理系统做维护,原来只有技术人员(月薪),市场销售人员(底薪+提成),经理(年薪+股份)三种运算算法,现在要增加兼职工作人员的(时薪)算法,但按
照上面的程序写法,公司就必须要把包含有的原三种算法的运算类给你,让你修改,你如果心中小算盘一打,‘TMD',公司给我的工资这么低,我真是郁闷,这会有机会了’,于是你除了增加了兼职算法以外,在技术人员(月薪)算法中写了一句
if (员工是小菜)
{
salary = salary * 1.1;
}
那就意味着,你的月薪每月都会增加10%(小心被抓去坐牢),本来是让你加一个功能,却使得原有的运行良好的功能代码产生了变化,这个风险太大了。
//运算类
class Operation { private double _numberA = 0; private double _numberB = 0; /// <summary> /// 数字A /// </summary> public double NumberA { get { return _numberA; } set { _numberA = value; } } /// <summary> /// 数字B /// </summary> public double NumberB { get { return _numberB; } set { _numberB = value; } } /// <summary> /// 得到运算结果 /// </summary> /// <returns></returns> public virtual double GetResult() { double result = 0; return result; } }
//加法类
class OperationAdd : Operation { public override double GetResult() { double result = 0; result = NumberA + NumberB; return result; } }
//减法类
class OperationSub : Operation { public override double GetResult() { double result = 0; result = NumberA - NumberB; return result; } }
//乘法类
class OperationMul:Operation { public override double GetResult() { double result = 0; result = NumberA * NumberB; return result; } }
//除法类
class OperationDiv : Operation { public override double GetResult() { double result = 0; if (NumberB == 0) throw new Exception("除数不能为0。"); result = NumberA / NumberB; return result; } }
//平方根运算类
class OperationSqrt:Operation { public override double GetResult() { double result = 0; if (NumberA >=0) result = Math.Sqrt(NumberA); return result; } }
//工厂模式类
/// <summary> /// 运算类工厂 /// </summary> class OperationFactory { public static Operation createOperate(string operate) { Operation oper = null; switch (operate) { case "+": { oper = new OperationAdd(); break; } case "-": { oper = new OperationSub(); break; } case "*": { oper = new OperationMul(); break; } case "/": { oper = new OperationDiv(); break; } case "Sqrt": { oper = new OperationSqrt(); break; } } return oper; //动态绑定,子类对象赋值给父类引用 } }
//通过主函数来进行测试
class Program { static void Main(string[] args) { try { Console.Write("请输入数字A:"); string strNumberA = Console.ReadLine(); Console.Write("请选择运算符号(+、-、*、/、Sqrt),平方根运算只运算数字A:"); string strOperate = Console.ReadLine(); Console.Write("请输入数字B:"); string strNumberB = Console.ReadLine(); Operation oper; oper = OperationFactory.createOperate(strOperate); oper.NumberA = Convert.ToDouble(strNumberA); oper.NumberB = Convert.ToDouble(strNumberB); string strResult = Convert.ToString(oper.GetResult()); Console.WriteLine("结果是:" + strResult); Console.ReadLine(); } catch (Exception ex) { Console.WriteLine("您的输入有错:" + ex.Message); } } }