简单工厂模式与工厂方法模式的对比
简单工厂模式:
UML图
首先来解释一下这个UML图
1、运算类是一个基类,包含了两个属性,一个虚方法getResult
2、加法类,减法类,乘法类,除法类分别继承于基类运算类,并且根据不同的类实例化出不同的虚方法getResult从而实现了多态
3、简单工厂类继承于运算类,主要封装了业务逻辑,根据不同的操作符实例化出不同的派生类(加法类、减法类、乘法类、除法类)。
下面是源码分析:
第一步:创建基类
#region 基类
class Operation
{
private double _number1;
private double _number2;
public double Number1
{
get { return this._number1; }
set { this._number1 = value; }
}
public double Number2
{
get { return this._number2; }
set { this._number2 = value; }
}
public virtual double getResult()
{
double result = 0;
return result;
}
}
#endregion
第二步:创建派生类
#region 四个派生类:加法类,减法类,乘法类,除法类
class OperationAdd : Operation
{
public override double getResult()
{
double result = Number1 + Number2;
return result;
}
}
class OperationSub : Operation
{
public override double getResult()
{
double result = Number1 - Number2;
return result;
}
}
class OperationMul : Operation
{
public override double getResult()
{
double result = Number1 * Number2;
return result;
}
}
class OperationDiv : Operation
{
public override double getResult()
{
double result = Number1 / Number2;
return result;
}
}
#endregion
第三步:创建简单工厂类
#region 工厂类
class OperationFactory : Operation
{
public static Operation createOperation(string strOperate)
{
Operation oper = null;
switch (strOperate)
{
case "+":
oper = new OperationAdd();
break;
case "-":
oper = new OperationSub();
break;
case "*":
oper = new OperationMul();
break;
case "/":
oper = new OperationDiv();
break;
}
return oper;
}
}
#endregion
好啦现在我们在Main函数中使用它们
class Program
{
static void Main(string[] args)
{
Console.WriteLine("请输入第一数字");
string strNumber1 = Console.ReadLine();
Console.WriteLine("请输入第二个数字");
string strNumber2 = Console.ReadLine();
Console.WriteLine("请输入操作符");
string strOperate = Console.ReadLine();
Operation oper = OperationFactory.createOperation(strOperate);//实例化对象
//为实例化的Operation对象传递了两个属性值
oper.Number1 = double.Parse(strNumber1);
oper.Number2 = double.Parse(strNumber2);
double result=oper.getResult();
Console.WriteLine(result.ToString());
Console.ReadKey();
}
}
运行结果如下:
从我们使用的Main函数我们可以看出,我们并没有任何的业务逻辑结构在里面,只是传递了两个属性变量和一个操作符,而客户端并不需要知道Operation到底做了什么,所有的业务逻辑封装到了Operation类及其派生类中。这样做将业务逻辑层和表现层很好的分离了。注意业务和表现层很好的分离。这是一个很伟大的思想,因为它让我们可以很好的重用这些代码,或者说可维护性很强。比如:网站建设中:后台代码与前台代码的分离,WPF中XAML语言与后台C#逻辑的分离等等。
好啦,现在我们来看一下比简单工厂更加神奇的工厂方法模式
工厂方法模式:定义了一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类
UML图
如图所示:我们把工厂类抽象为一个接口,这个接口只有一个方法,就是创建抽象产品的工厂方法。然后所有要生成具体类的工厂,就去实现这个接口。
下面是源码分析:
第一步:基类设计
#region 基类
class Operation
{
private double _number1;
private double _number2;
public double Number1
{
get { return this._number1; }
set { this._number1 = value; }
}
public double Number2
{
get { return this._number2; }
set { this._number2 = value; }
}
//创建一个虚方法
public virtual double getResult()
{
double result = 0;
return result;
}
}
#endregion
第二步:派生类设计
#region 派生类继承于基类Operation,并分别重写了虚方法
class OperationAdd : Operation
{
public override double getResult()
{
double result = Number1 + Number2;
return result;
}
}
class OperationSub : Operation
{
public override double getResult()
{
double result = Number1 - Number2;
return result;
}
}
class OperationMul : Operation
{
public override double getResult()
{
double result = Number1 * Number2;
return result;
}
}
class OperationDiv : Operation
{
public override double getResult()
{
double result = Number1 / Number2;
return result;
}
}
#endregion
第三步:创建一个接口,抽象工厂,所有的派生工厂类都实现这个接口
#region 抽象工厂
//创建一个接口
interface IOperationFactory
{
Operation createOperation();
}
#endregion
第四步:派生工厂类设计
#region 派生工厂类 真正实例化了Operation对象
//该类为加法工厂类,继承于父类OperationFactory,并实例化createOperation方法并输入OperationAdd对象
class OperationFactoryAdd : IOperationFactory
{
public Operation createOperation()
{
return new OperationAdd();
}
}
//该类为减法工厂类,继承于父类OperationFactory,并实例化createOperation方法输出OperationSub对象
class OperationFactorySub : IOperationFactory
{
public Operation createOperation()
{
return new OperationSub();
}
}
//该类为乘法工厂类,继承于父类OperationFactory,并实例化createOperation方法输出OperationMul对象
class OperationFactoryMul : IOperationFactory
{
public Operation createOperation()
{
return new OperationMul();
}
}
//该类为除法工厂类,继承于父类OperationFactory,并实例化createOperation方法输出OperationDiv对象
class OperationFactoryDiv : IOperationFactory
{
public Operation createOperation()
{
return new OperationDiv();
}
}
#endregion
通过派生的工厂类,我们实际上实例化了Operation对象
下面我们来看下客户端代码实现:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("请输入两个数字");
string strNumber1 = Console.ReadLine();
string strNumber2 = Console.ReadLine();
double douNumber1 = double.Parse(strNumber1);
double douNumber2 = double.Parse(strNumber2);
//先实例化一个工厂方法再创建Operation派生对象
IOperationFactory operFactory = new OperationFactoryAdd();//实例化了一个加法工厂
Operation objOperation = operFactory.createOperation();//从加法工厂类得到实例的求平均值类
objOperation.Number1 = douNumber1;//给Operation的两个属性赋值
objOperation.Number2 = douNumber2;
//调用getResult方法
double result=objOperation.getResult();
Console.WriteLine(result.ToString());
Console.ReadKey();
}
}
从客户端实现代码我们可以看出 :首先实例化了一个抽象工厂接口,再由实例化得到的工厂类去得到对应的实例化的Operation派生类。
我们大家可以看到,工厂方法模式与简单工厂模式有着一定的相似性,虽然两者实现了相同的功能(记住千万不要拿实现功能就OK来评价一个程序或者代码设计,那是很不负责的一种态度。而要在功能实现的基础上考虑程序的健壮性,可扩展性,可重用性等)同时工厂方法模式明显比简单工厂模式要复杂的多。那么为什么我们就用简单工厂就可以完成任务行吗?
好啦,如果我们的需求变了,需要再添加一个功能,比如说求两个数的平均值。
简单工厂模式的做法是:
在基类下派生出一个新的类出来,同时必须还要改的一个地方是简单工厂类,在这里面加上一个case的判断,但是这明显是在修改逻辑代码。类的设计原则是不应该修改类的结构或者代码。它违背了Open-Close原则,模式的设计只能对类进行扩展,不能对类进行修改。就好比我们计算机的插槽,CPU只提供了接口,我们要插什么只要在外部插上需要的硬件就行啦,而我们并不能修改CPU里面的结构等其他东西。这就保证了CPU内部工作的稳定性。同样这也是一样的,Open-Close原则也在一定的程度上保证了类设计的稳定性。
那么如果工厂方法模式的做法是:
在基类下派生出一个新的类,同时,在抽象工厂中派生出新的工厂方法。这两个类的设计都只是扩展了原有的类或者接口的设计,并没有去修改原有的类或者结构。
所以工厂方法模式是简单工厂模式的进一步抽象和推广。
好啦今天就总结到这里:详细内容请大家查阅大话设计模式或者GOF书籍