前面我们讲述了简单工厂模式,提到其缺点是系统难以扩展,一旦添加新产品就不得不修改简单工厂方法,这样造成简单工厂方法的实现逻辑过于复杂。本节介绍的工厂方法模式可以解决这个问题。
一、定义
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
二、结构图
三、实例
与简单工厂一致,我们先构建运算类,然后各运算子类继承该基类
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( )
{
double result = 0;
result = NumberA + NumberB;
return result;
}
}
public class OperationSub : Operation
{
public override double GetResult( )
{
double result = 0;
result = NumberA - NumberB;
return result;
}
}
public class OperationMul : Operation
{
public override double GetResult( )
{
double result = 0;
result = NumberA * NumberB;
return result;
}
}
public class OperationDiv : Operation
{
public override double GetResult( )
{
double result = 0;
result = NumberA / NumberB;
return result;
}
}
之前简单工厂模式的做法是:将所有的负责运算的对象集中在一起,构成一个生产运算法则的类,然后通过该类去实现各种运算,如下所示:
public class OperationFactory
{
/// <summary>
/// 简单工厂模式:负责生产对象的一个类,本例负责生产运算对象
/// </summary>
/// <param name="operate"></param>
/// <returns></returns>
public static Operation createOperation( 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;
}
}
static void Main( string[ ] args )
{
Operation oper;
string str_oper = "+";
oper = OperationFactory.createOperation( str_oper );
oper.NumberA = 1;
oper.NumberB = 2;
double result = oper.GetResult( );
Console.WriteLine( "{0} {1} {2} = {3}", oper.NumberA, str_oper, oper.NumberB, result );
Console.Read( );
}
这种运算方式的逻辑结构图如下:
而工厂方法模式,它的实现是把具体产品的创建推迟到子类中,此时工厂类不再负责所有产品的创建,而只是给出具体工厂必须实现的接口,这样工厂方法模式就可以允许系统不修改工厂类逻辑的情况下来添加新产品,这样也就克服了简单工厂模式中缺点。
如下所示,先构建一个工厂接口:
//先构建一个工厂接口
interface IFactory
{
Operation CreateOperation( );
}
然后根据运算种类各建一个具体工厂去实现这个接口:
public class AddFactory : IFactory
{
public Operation CreateOperation( )
{
return new OperationAdd( );
}
}
public class SubFactory : IFactory
{
public Operation CreateOperation( )
{
return new OperationSub( );
}
}
public class MulFactory : IFactory
{
public Operation CreateOperation( )
{
return new OperationMul( );
}
}
public class DivFactory : IFactory
{
public Operation CreateOperation( )
{
return new OperationDiv( );
}
}
最后,各运算工厂实现自己的运算方法:
static void Main( string[ ] args )
{
IFactory operFactory = new AddFactory( );
Operation oper = operFactory.CreateOperation( );
oper.NumberA = 1;
oper.NumberB = 2;
double result = oper.GetResult( );
Console.WriteLine( "{0} {1} {2} = {3}", oper.NumberA, "+", oper.NumberB, result );
Console.Read( );
}
实现结构图:
四、总结
工厂方法模式实现时,客户端需要决定实例化哪一个工厂来实现运算类,选择判断的问题还是存在,也就是说,工厂方法把简单工厂的内部逻辑判断移动到客户端代码进行。
使用工厂方法实现的系统,如果系统需要添加新产品时,我们可以利用多态性来完成系统的扩展,对于抽象工厂类和具体工厂中的代码都不需要做任何改动。
工厂方法模式是为了克服简单工厂模式的缺点而设计出来的,简单工厂模式的工厂类随着产品类的增加需要增加额外的代码),而工厂方法模式每个具体工厂类只完成单个实例的创建,所以它具有很好的可扩展性。但是在现实生活中,一个工厂只创建单个产品这样的例子很少,因为现在的工厂都多元化了,一个工厂创建一系列的产品,如果我们要设计这样的系统时,工厂方法模式显然在这里不适用,不过抽象工厂模式可以很好地解决一系列产品创建的问题。我们在下一章节进行介绍。