第01章 代码无错就是优?——简单工厂模式
版本1:
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);
}
}
以上代码至少存在以下3个问题:
1:变量命名不规范。
2:使用了四次 if 而不是if else结构,意味着做了多次无用功。
3:没有对用户输入内容做合法性校验。
版本2:
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.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(“你的输入有错:”+ex.Message);
}
}
}
1.4 面向对象编程
很多人都有这样的问题:就是碰到问题就直觉地用计算机能够理解的逻辑来描述和表达待解决的问题及具体的求解过程。这其实就是用计算机的方式去思考,这样的思维使得我们的程序不易维护,不易扩展,更不易复用。
1.5 活字印刷,面向对象
以活字印刷为例:第一,要改,只需要更改要改之字,此为可维护;第二,这些字并非这次用完就无用,完全可以在后来的印刷中重复使用,此乃可复用;第三,若要加字,只需要另外刻字加入即可,这是可扩展;第四:若要由横拍印刷转为竖排印刷,只要重新排序即可,此为灵活性好。
1.6 面向对象的好处
通过封装、继承、多态把程序的耦合度降低。用设计模式使得程序更加的灵活,容易修改,并且易于复用。
1.8 业务的封装
让业务逻辑与界面逻辑分开,让他们之间的耦合度下降。只有分离,才可以达到容易维护或扩展。
版本3:
Operation运算类:
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;
}
}
客户端代码
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);
}
}
1.9 紧耦合VS松耦合
观察上面的代码可发现,如果需要新增加一种运算类型,将会很麻烦,需要修改原有的运算类。
版本4-1:
Operation 运算类
public class Operation
{
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;
}
}
加减乘除类:
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;
}
}
1.10 简单工厂模式
现在的问题是实例化哪个对象的问题,到底是实例化谁,将来会不会增加实例化的对象,比如增加开根运算,这是很容易变化的地方,可以考虑用一个单独的类来做这个创造实例的过程,这就是简单工厂。
版本4-2:
public 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;
}
return oper;
}
}
客户端代码:
Operation oper;
oper = OperationFactory.createOperate(“+”);
oper.NumberA = 1;
oper.NumberB = 2;
double result = oper.GetResult();
此时如果需要增加新运算只需要增加运算累和修改简单工厂类即可。
结构图:
其中空心三角形+实线表示继承关系,箭头+虚线表示依赖(dependency)关系
简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。但是简单工厂模式违反了开放-封闭原则,如果要添加新的产品就要修改简单工厂类,这就等于说,我们不但对扩展开放,对修改也开放。
method |ˈmeθəd| noun:方法.
工厂方法模式(Factory Method),定义了一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。工厂方法模式实现时,客户端需要决定实例化那一个工厂来生产产品,选择判断的问题还是存在的,也就是说,工厂方法把简单工厂的内部逻辑判断移动到了客户端代码来进行。你想要加功能,本来是改工厂类的,而现在是修改客户端。
1:void |vɔɪd| noun:空白、空虚。
2:console |ˈkɒnsəʊl| noun:(control panel)控制面板、(control system)控制台。
3:convert |kənˈvɜːt| verb:转变、换算。
4:exception |ɪkˈsepʃn| noun:例外。
5:switch |swɪtʃ| noun:开关。
6:salary |ˈsæləri| noun:薪水。
7:override |ˌəʊvəˈraɪd| verb:否决、使…无效。
8:virtual |ˈvɜːtʃʊəl| adj:虚拟的。
9:subtract |səbˈtrækt| verb:减去。
10:multiply |ˈmʌltɪplaɪ| verb:乘。
11:divide |dɪˈvaɪd| verb:分、划分、分隔。