《大话设计模式》这本书现在已经到了总结的阶段,翻看目录,23个模式+6个基本原则,but为什么我看到了24个模式???第一反应,盗版书!!!However,遇到问题要先从自己的角度分析,经过查资料,<简单工厂模式>又名<静态工厂方法模式>不属于23个模式之中,So,疑惑解答了,But,我认为这个模式在学习这本书的过程中起到了承前启后的作用,是对面向对象思想的高度浓缩,下面就来对其进行细致的分析吧。
考官:请设计一个计算器的程序,要求:体现出面向对象思想中的封装、继承、多态三大特性,程序规范、合理,请在有效时间内完成答题。
考生1:
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 “-”;
//同上
case “*”:
//同上
Break;
case “/”:
//同上
Break;
Console.WriteLine(“结果是:”+strResult);
Console.ReadLine();
}
Catch (Exception ex)
{
Console.WriteLine(“您的输入有错:”+ex.Message);
}
}
}
考生2:
namespace 简单工厂
{
public class Operation //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;
}
}
public class OperationAdd : Operation //具体的加法类,继承于Operation运算类
{
public override double GetResult()
{
double result=0;
result=NumberA+NumberB;
return result;
}
}
public class OperationSub : Operation //具体的减法类,继承于Operation运算类
{
public override double GetResult()
{
double result = 0;
result = NumberA - NumberB;
return result;
}
}
public class OperationMul : Operation //具体的乘法类,继承于Operation运算类
{
public override double GetResult()
{
double result = 0;
result = NumberA * NumberB;
return result;
}
}
public class OperationDiv : Operation //具体的除法类,继承于Operation运算类
{
public override double GetResult()
{
double result = 0;
if (NumberB == 0)
throw new Exception("除数不能为0;");
result = NumberA /NumberB;
return result;
}
}
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;
}
}
class Program //客户端代码,即界面逻辑。
{
static void Main(string[] args)
{
Operation oper;
oper = OperationFactory.createOperate("+");
oper.NumberA = 3;
oper.NumberB = 4;
double result=oper.GetResult();
Console.Write(result);
}
}
}
考官:请两位考生分别对自己所写代码进行介绍说明:
考生一:
考官,您好!
由于这个程序比较简单,在上学的过程中已经非常熟练,我在设计的过程中用了5分钟就设计出来了,我的编程能力很强。程序设计中我用到了“异常处理机制”,我的代码只要在运行过程中有问题就能自动报错,而且设计过程中逻辑清晰,运用了分支结构,很快我就完成了这个题目。
考官:“嗯,你的编程速度确实很快,在学习里应该是个高手,下面来听听第二个考生的讲解”。
考生二:
“考官,您好!
在这个程序设计之前,我想到了在学习里曾经设计过这样简单的程序,而且随着深入的学习,我接触过面向对象的思维之后,我就想着能不能用面向对象的思想来设计这个“计算器”,于是我编码的时间长了一点,但是也在规定的时间内完成了。
由于用到了面向对象的思想,我在程序设计之前先画了UML图,如下所示:我的程序的亮点在于我用到了‘简单工厂模式’,如上图所示是我对这个程序的一个抽象,同时我的程序可以真正的做到“可复用”、“可维护”、“可扩展”。”
考官:很好,具体谈谈你的思路。
考生二:
首先,我认为面向对象中三大特性的使用说白了就是这么一个对应关系即:
封装性 |
继承性 |
多态性 |
可复用 |
可维护 |
可扩展 |
考生二接着开始对他的代码介绍:
1、 业务逻辑与界面逻辑的分离---复用性、封装性
看了考生1的代码,核心业务and界面程序段都写在了Main()之中,这样的话,界面与业务的关联程度太大了,即耦合性太强,要是我需要改变界面,修改代码的同时可能业务上的代码会被无意间改动,岂不是让程序的维护困难很大吗?
我觉得封装性的实现才是保证继承性和多态性的基础啊(纯属个人谬论),于是我将实际参加运算的代码与界面调用它的代码分离开来,也就是在void Main()的基础上,定义一个Operation类,专门用于算数,这样保证了即使以后我要重新用这个业务代码(Operation),只要重写一个界面就OK了,不在让他们藕断丝连了。
2、 运算类基类的抽象---可维护性、继承性
但是在运算类Operation中,我发现它需要将加减乘除四种方法都写在一起,这就很类似于收音机中各个二极管、三极管、电阻聚集在一起,一旦其中某个部件坏了,我的收音机也就挂掉了,我想我的这段代码如果想要日后进行修改不能设计成收音机的这种形式,而应该是PC机主板的那种形式,这样的话,我不得不去抽象出个基类,然后四种加减乘除关系去继承这个类,(主要是对方法的继承),这样呢,及时我需要修改加运算,我也仅仅需要去修改我上面代码中的OperationAdd这个类就可以了,同时这也验证了我刚才所说的那个观点,即实现了复用性才有维护性啊!,哈哈,这也不是没有道理啊。
可是此处有一个需要注意的地方,如果运算的方法即派生类过多的话,这种模式是非常不利于维护的,待会说明。
3、 增加简单工厂---可扩展、多态性
我记得在六个原则里有一条叫做“开放-封闭原则”,意思是对于扩展是开放,而对于修改是封闭的。我所设计的这个程序就有这种功能,结合程序代码,publicclassOperationFactory //简单工厂类即可轻松的实现,比如说现在增加开方的一个类,仅需两步,增加运算子类,修改OperationFactory中的switch条件,即实现了扩展,也就是增加:
Class OperationSq:Operation
{
Public override double GetResult()
{
Double result1=0;
Double result2=0;
Result1=NumberA*numberA;
Result2=NumberB*NumberB;
Return result1;
Return result2;
}
}
在OperationFactory中增加:
Case “^”:
Oper=new OperationSq();
Break;
即可。
这样,我的代码中对面向对象三大特性的体现就都实现了。
考官:
Terrific.
你通过对‘简单工厂模式’的应用,把如何复用、怎么为维护创造条件、如何扩展程序都说的非常好,你觉得你程序设计最为出彩的地方是哪里?
考生二:
在于OperationFactory类的运用,我觉得这就是所谓的“程序眼”吧,工厂类依赖于抽象出的运算类,在工厂中进行选择具体的运算,从而使得客户端不和具体运算类直接发生调用关系,通过抽象类在工厂中实例化,然后去执行相应的操作,这很类似于中国古代的皇权,什么事情都由自己来处理,这样确保了集中化,但是如果操作过多的话,也会出现问题,比如皇上病了,朝廷上所有的事情就不能处理了,就是说如果子类过多的话,会造成工厂和子类之间高度的耦合,反而运用了模式后却坏了事情。
总而言之,通过对简单工厂模式的应用,对于这个运算子类不多的小程序,可以时间复用、维护、扩展这些基本需求,很方便上手,但是要用到其他系统里可能就不太合适了。
考生二在被公司高薪资录用的同时也为我们对于简单工厂模式做了详细的分析,预祝他的路越走越远。