我现在想改变我的代码面貌,因为我现在写的代码是脆弱的,僵化的,不易于扩展。所以准备以面向对象和设计模式对代码进行一番改造。
我现在的代码面貌:
代码1:
namespace Study4
{
class Program
{
static void Main(string[] args)
{
try
{ /*
在这里,业务逻辑与界面逻辑没有分离
*/
Console.WriteLine("请输入数字A:");
string strNumberA = Console.ReadLine();
Console.WriteLine("请选择运算符号(+,-,*,/):");
string strOperate = Console.ReadLine();
Console.WriteLine("请输入数字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("结果是:{0}",strResult);
Console.ReadLine();
}
catch(Exception ex)
{
Console.WriteLine("您的输入有错:{0}",ex.Message);
}
}
}
上面这段代码是我借于《大话设计模式》的范例,可以很好的体现我如今编写代码的现状。观察上述的代码,可以看出它的业务逻辑与界面逻辑混合冗杂在一起,没有分离。
在这里,解释一下业务逻辑和界面逻辑。
业务逻辑:根据用户需求来处理数据,是系统的核心
界面逻辑:接受用户输入的数据和它显示的数据
业务逻辑与界面逻辑分离的优势:减少了代码之间的耦合度
根据上面论述,我们来对代码1进行业务逻辑与界面逻辑的分离改造:
代码2
界面代码:
namespace Study4
{
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("请输入数字A:");
string strNumberA = Console.ReadLine();
Console.WriteLine("请选择运算符号(+,-,*,/):");
string strOperate = Console.ReadLine();
Console.WriteLine("请输入数字B:");
string strNumberB = Console.ReadLine();
string strResult = "";
Operation _operation = new Operation();
strResult = _operation.GetResult(Convert.ToDouble(strNumberA),
Convert.ToDouble(strNumberB), strOperate).ToString();
Console.WriteLine("结果是:{0}",strResult);
Console.ReadLine();
}
catch(Exception ex)
{
Console.WriteLine("您的输入有错:{0}",ex.Message);
}
}
}
}
业务逻辑代码:
class Operation//让业务逻辑与界面逻辑分离
{
public 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;
}
}
针对代码2中的业务逻辑类代码进一步来分析,就会发现,如果我们需要增加"开根"的话,就需要更改我们已经封装好的Operation类,这会带来不可预知的风险,因为仅仅只需要增加开根算法,使得已有的四种算法逻辑暴露在我们面前,如果不小心动了已经存在的算法源码,这会是软件系统的原有功能产生变化。所以仔细思考,我们设计的Operation类违背了单一原则,就是一个类只存在一个变化量。那么进一步对代码2进行重构。
代码3:
界面代码:
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("请输入数字A:");
string strNumberA = Console.ReadLine();
Console.WriteLine("请选择运算符号(+,-,*,/):");
string strOperate = Console.ReadLine();
Console.WriteLine("请输入数字B:");
string strNumberB = Console.ReadLine();
string strResult = "";
switch (strOperate)
{
case "+":
Operation operateAdd = new OperationAdd();
operateAdd._numberA = Convert.ToDouble(strNumberA);
operateAdd._numberB = Convert.ToDouble(strNumberB);
strResult= operateAdd.GetResult().ToString();
break;
case "-":
Operation operateSub = new OperationSub();
operateSub._numberA = Convert.ToDouble(strNumberA);
operateSub._numberB = Convert.ToDouble(strNumberB);
strResult = operateSub.GetResult().ToString();
break;
case "*":
Operation operateMul = new OperationMul();
operateMul._numberA = Convert.ToDouble(strNumberA);
operateMul._numberB = Convert.ToDouble(strNumberB);
strResult = operateMul.GetResult().ToString();
break;
case "/":
Operation operateDiv = new OperationDiv();
operateDiv._numberA = Convert.ToDouble(strNumberA);
operateDiv._numberB = Convert.ToDouble(strNumberB);
strResult = operateDiv.GetResult().ToString();
break;
}
Console.WriteLine("结果是:{0}",strResult);
Console.ReadLine();
}
catch(Exception ex)
{
Console.WriteLine("您的输入有错:{0}",ex.Message);
}
}
}
业务逻辑代码:
public class Operation//让业务逻辑与界面逻辑分离
{
public double _numberA { get; set; }
public double _numberB { get; set; }
public virtual double GetResult()
{
double result = 0;
return result;
}
}
public class OperationAdd : Operation
{
public override double GetResult()
{
return _numberA+_numberB;
}
}
public class OperationSub : Operation
{
public override double GetResult()
{
return _numberA-_numberB;
}
}
public class OperationMul : Operation
{
public override double GetResult()
{
return _numberA*_numberB;
}
}
public class OperationDiv : Operation
{
public override double GetResult()
{
if (_numberB == 0)
{
throw new Exception("除数不能为0");
}
return _numberA/_numberB;
}
}
仔细观察代码3的界面代码,相比以前代码行数还增加了,但是相对而言,界面代码与业务逻辑代码的耦合度降低了,而且业务代码的可扩展性增强了。但是我们仍可以从页面代码中再次封装一个业务逻辑就是对于输入运算符的控制,所以我们可以进一步重构代码:
代码4
界面代码:
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("请输入数字A:");
string strNumberA = Console.ReadLine();
Console.WriteLine("请选择运算符号(+,-,*,/):");
string strOperate = Console.ReadLine();
Console.WriteLine("请输入数字B:");
string strNumberB = Console.ReadLine();
string strResult = "";
Operation operate = null;
OperationFactory operationFactory = new OperationFactory();
operationFactory._operation = strOperate;
operate = operationFactory.CreateOpeate();
operate._numberA = Convert.ToDouble(strNumberA);
operate._numberB = Convert.ToDouble(strNumberB);
strResult = operate.GetResult().ToString();
Console.WriteLine("结果是:{0}",strResult);
Console.ReadLine();
}
catch(Exception ex)
{
Console.WriteLine("您的输入有错:{0}",ex.Message);
}
}
}
业务逻辑代码1:
public class Operation//让业务逻辑与界面逻辑分离
{
public double _numberA { get; set; }
public double _numberB { get; set; }
public virtual double GetResult()
{
double result = 0;
return result;
}
}
public class OperationAdd : Operation
{
public override double GetResult()
{
return _numberA+_numberB;
}
}
public class OperationSub : Operation
{
public override double GetResult()
{
return _numberA-_numberB;
}
}
public class OperationMul : Operation
{
public override double GetResult()
{
return _numberA*_numberB;
}
}
public class OperationDiv : Operation
{
public override double GetResult()
{
if (_numberB == 0)
{
throw new Exception("除数不能为0");
}
return _numberA/_numberB;
}
}
业务逻辑代码2:
public Operation CreateOpeate()
{
Operation op = null;
switch (_operation)
{
case "+":
op = new OperationAdd();//在这里体现出了类的多态性
break;
case "-":
op = new OperationSub();
break;
case "*":
op = new OperationMul();
break;
case "/":
op = new OperationDiv();
break;
}
return op;
}
写到这里,相信大家不难发现,这是简单的工厂模式,但是代码4的代码仍然存在着瑕疵。
类图如下: