简单工厂模式(2)

一、举例

用控制台程序做一个非常简单的计算机,实现加减乘除运算即可,那么,大家自然而然的会写出如下代码

 1 static void Main(string[] args)
 2         {
 3             Console.WriteLine("请输入数字A:");
 4             string strNumA = Console.ReadLine();
 5             Console.WriteLine("请选择运算符号(+、-、*、、)");
 6             string strOperate = Console.ReadLine();
 7             Console.WriteLine("请输入数字C:");
 8             string strNumB = Console.ReadLine();
 9             string strResult = "";
10             if (strOperate == "+")
11             {
12                 strResult = Convert.ToString(Convert.ToDouble(strNumA) + Convert.ToDouble(strNumB));
13             }
14             if (strOperate == "-")
15             {
16                 strResult = Convert.ToString(Convert.ToDouble(strNumA) - Convert.ToDouble(strNumB));
17             }
18             if (strOperate == "*")
19             {
20                 strResult = Convert.ToString(Convert.ToDouble(strNumA) * Convert.ToDouble(strNumB));
21             }
22             if (strOperate == "/")
23             {
24                 strResult = Convert.ToString(Convert.ToDouble(strNumA) / Convert.ToDouble(strNumB));
25             }
26             Console.WriteLine($"结果是:{strResult}");
27             Console.ReadKey();
28         }

二、演绎

1、第一步演绎

①由于在判断运算符时,用的是if语句,这意味着每个条件都需要做判断,相当于计算机做了三次无用功。

②没有输入校验,例如,除数不能为零的问题等等

就上述两个问题,做如下修改:(输入校验此处先只做除数为零的校验)

 1 static void Main(string[] args)
 2         {
 3             Console.WriteLine("请输入数字A:");
 4             string strNumA = Console.ReadLine();
 5             Console.WriteLine("请选择运算符号(+、-、*、、)");
 6             string strOperate = Console.ReadLine();
 7             Console.WriteLine("请输入数字C:");
 8             string strNumB = Console.ReadLine();
 9             string strResult = "";
10             switch (strOperate)
11             {
12                 case "+":
13                     strResult = Convert.ToString(Convert.ToDouble(strNumA) + Convert.ToDouble(strNumB));
14                     break;
15                 case "-":
16                     strResult = Convert.ToString(Convert.ToDouble(strNumA) - Convert.ToDouble(strNumB));
17                     break;
18                 case "*":
19                     strResult = Convert.ToString(Convert.ToDouble(strNumA) * Convert.ToDouble(strNumB));
20                     break;
21                 case "/":
22                     if (strNumB != "0")
23                     {
24                         strResult = Convert.ToString(Convert.ToDouble(strNumA) / Convert.ToDouble(strNumB));
25                     }
26                     else
27                     {
28                         strResult = "除数不能为0";
29                     }
30                     break;
31             }
32             Console.WriteLine($"结果是:{strResult}");
33             Console.ReadKey();
34         }

2、第二步演绎

①上述写的简单的计算器仅仅体现了面向过程的编程,没有体现面向对象的编程

②上述代码使用控制台应用实现的,假如有一天我需要用Winform、Web 等实现一模一样的需求,那么,上述代码则需要重新编写,好可怕。

就上述问题,做如下修改:

将业务逻辑与界面分离

Operation运算类

 1 public class Operation
 2     {
 3         public static double GetResult(double numA, double numB, string strOperate)
 4         {
 5             double result = 0d;
 6             switch (strOperate)
 7             {
 8                 case "+":
 9                     result = numA + numB;
10                     break;
11                 case "-":
12                     result = numA - numB;
13                     break;
14                 case "*":
15                     result = numA * numB;
16                     break;
17                 case "/":
18                     result = numA / numB;
19                     break;
20             }
21             return result;
22         }
23     }

客户端

 1 static void Main(string[] args)
 2         {
 3             try
 4             {
 5                 Console.WriteLine("请输入数字A:");
 6                 string strNumA = Console.ReadLine();
 7                 Console.WriteLine("请选择运算符号(+、-、*、、)");
 8                 string strOperate = Console.ReadLine();
 9                 Console.WriteLine("请输入数字C:");
10                 string strNumB = Console.ReadLine();
11                 string strResult = "";
12                 strResult = Convert.ToString(Operation.GetResult(Convert.ToDouble(strNumA), Convert.ToDouble(strNumB), strOperate));
13                 Console.WriteLine($"结果是:{strResult}");
14                 Console.ReadKey();
15             }
16             catch (Exception ex)
17             {
18                 Console.WriteLine($"您的输入有错:{ex.Message}");
19             }
20         }

这样的话,无论是控制台,还是Winform以及其他应用,只需要调用 Operation 这个类即可了。实现了业务逻辑与界面的分离。这里,也用到了面向对象编程的三大特性之一的封装。

3、第三步演绎

①如果我想增加一种计算方式,例如开根号(sqrt)运算怎么办,只能是修改Operation类,在switch中增加一种情况。

②针对①问题做修改的话,那么另一个问题就来了,我修改Oeration类的时候,之前写好的加减乘除功能全在其中,如果我不小心,或者有意搞破坏,将本来运行的好好的加减乘除功能改掉,怎么办?(此例中仅仅是计算器,如果换做是成熟的产品,或者涉及到资金运算等等的代码,运行的好好的,不可能会让程序员在其中胡作非为的)

针对上述问题,作如下修改:

我可以将加减乘除各种运算分别封装到不同的类里面,这样,就能解决②的问题,每增加一种运算,我就增加一个类,这样①问题也解决了。

首先,将不同的运算抽象出一个共同的类,即父类

 1 public class Operation
 2     {
 3         private double _numberA = 0;
 4         private double _numberB = 0;
 5         public double NumberA
 6         {
 7             get
 8             {
 9                 return _numberA;
10             }
11 
12             set
13             {
14                 _numberA = value;
15             }
16         }
17         public double NumberB
18         {
19             get
20             {
21                 return _numberB;
22             }
23 
24             set
25             {
26                 _numberB = value;
27             }
28         }
29         public virtual double GetResult()
30         {
31             double result = 0;
32             return result;
33         }
34     }

其次,让不同的运算继承这个父类,然后根据不同的运算,重写父类中的GetResult方法

 1 //加法类
 2     public class OperationAdd:Operation
 3     {
 4         public override double GetResult()
 5         {
 6             double result = 0;
 7             result = NumberA + NumberB;
 8             return result;
 9         }
10     }
11     //减法类
12     public class OperationSub : Operation
13     {
14         public override double GetResult()
15         {
16             double result = 0;
17             result = NumberA = NumberB;
18             return result;
19         }
20     }
21     //乘法类
22     public class OperationMul : Operation
23     {
24         public override double GetResult()
25         {
26             double result = 0;
27             result = NumberA * NumberB;
28             return result;
29         }
30     }
31     //除法类
32     public class OperationDiv : Operation
33     {
34         public override double GetResult()
35         {
36             double result = 0;
37             if (NumberB==0)
38             {
39                 throw new Exception("除数不能为0");
40             }
41             result = NumberA / NumberB;
42             return result;
43         }
44     }

这样,上述的两个问题就迎刃而解了。

4、第四步演绎

到了简单工厂最核心的地方了。

 这么多的类,客户端该如何用这些类呢,换句话说,客户端如何实例化这些类呢?那么,就需要一个核心的东西——工厂,这个工厂负责给客户端提供他想要的类的实例。我想要实例化什么类,告诉工厂就可以了。

代码如下:

 1 public class OperationFactory
 2     {
 3         public static Operation createOperate(string operate)
 4         {
 5             Operation oper = null;
 6             switch (operate)
 7             {
 8                 case "+":
 9                     oper = new OperationAdd();
10                     break;
11                 case "-":
12                     oper = new OperationSub();
13                     break;
14                 case "*":
15                     oper = new OperationMul();
16                     break;
17                 case "/":
18                     oper = new OperationDiv();
19                     break;
20             }
21             return oper;
22         }
23     }

注意一点,这个工厂中的方法,返回的是加减乘除这些类的父类。

好了,制造类实例的工厂有了,那么,客户端只需要告诉工厂,给我造一个什么类的实例,然后用这个实例就可以了。

客户端代码如下

 1 static void Main(string[] args)
 2         {
 3             Operation oper;
 4             //告诉工厂,给我一个加法类的实例
 5             oper = OperationFactory.createOperate("+");
 6             oper.NumberA = 1;
 7             oper.NumberB = 2;
 8             double result = oper.GetResult();
 9             Console.WriteLine(result);
10             Console.ReadKey();
11         }

 经过上述一系列的演绎,也就形成了简单工厂模式。

三、总结

简单工厂模式,即 通过一个‘工厂类’,用于子类返回父类对象。


工厂模式结束,下一次,将讲解策略模式 

posted @ 2016-12-30 13:10  萌萌丶小魔王  阅读(546)  评论(2编辑  收藏  举报