工厂家族是指创建型模式中的三个名称很相像的模式,即简单工厂、工厂方法和抽象工厂模式,鼎鼎大名的工厂家族使我们编写代码更加简练,更加容易维护、扩展和复用,虽然工厂家族们有其各自的优点,但同时局限性也是不可避免的,下面对三工厂进行一个简单的总结。
一、简单工厂模式
简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例,其实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。主要是解决如何去实例化对象的问题,下面以实现计算器功能为例:
namespace 简单工厂模式
{
class Program
{
static void Main(string[] args)
{
try
{
Console.Write("请输入数字A:");
int strNumberA = Convert.ToInt32(Console.ReadLine()); //隐式转换
Console.Write("请选择运算符号(+、-、*、/)");
string stroperate = Console.ReadLine();
Console.Write("请输入数字B");
int strNumberB = Convert.ToInt32(Console.ReadLine());
Operation oper;
oper = OperationFactory.createOperate("strOperation"); //获取运算符
oper.NumberA = strNumberA; //NumberA赋值
oper.NumberB = strNumberB; //NumberB赋值
double result = oper.GetResult(); //数值计算,获得结果
Console.WriteLine(result);
}
catch (Exception ex)
{
Console.WriteLine("您的输入有错:" + ex.Message);
}
}
}
//简单运算工厂类
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运算类
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() //继承父类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;
}
}
优点:工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。
缺点:简单工厂严格来说并不算一种设计模式,因为它违反了开放-封闭原则,简单工厂是通过分支来判断选择实例化哪一个类,如果需求更改,那么就要更改工厂类了,不仅对扩展开放了,对修改也开放了。
二、工厂方法模式
工厂方法模式主要针对的是开放-封闭原则,它定义一个用于创建对象的借口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类。也就是说,在子类中去实例化对象,让子类做到需要什么就实例化什么。还以计算器为例:
关键代码:
//工厂借口
interface IFactory
{
Operation CreateOperation();
}
//具体工厂类(减法、乘法、除法同加法类)
class AddFactory : IFactory //加法类工厂
{
public Operation CreateOperation()
{
return new OperationAdd();
}
}
//客户端实现
IFactory operFactory = new AddFactory(); //实例化加法类工厂
Operation oper=operFactory.CreateOperation (); //实例化加法运算类
oper.NumberA = 1;
oper.NumberB = 2;
double result = oper.GetResult();
工厂方法模式实现时,客户端需要决定实例化哪一个工厂来实现运算类,也就是说将简单工厂的内部逻辑判断移到了客户端代码来进行,那么如果增加算法的话,虽然不用去改工厂类的case分支,但是需要到客户端去修改了。
工厂方法模式式简单工厂模式的进一步抽象和推广,由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。但缺点是由于每加一个产品,就需要加一个产品工厂的类,增加了额外的开发量。
三、抽象工厂模式
抽象工厂模式,提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。以数据访问程序为例,如果数据库中只有一个User表,那么使用简单工厂模式,定义一个IUser接口和访问IUser的工厂接口就可以实现了,但如果再增加一个Department表,那么就要用抽象工厂模式了,在工厂接口中增加接口方法,也要在工厂类中增加实例化方法。
关键代码:
//SqlserverDepartment类,用于访问SQL Server的Department
class sqlserverDepartment : IDepartment
{
public void Insert(Department department)
{
Console.WriteLine ("在SQL Server中给Department表增加一条记录");
}
public Department GetDepartment(int id)
{
Console.WriteLine("在SQL Server中根据ID得到Department表一条记录");
return null;
}
}
//IFactory接口,定义一个创建访问Department表对象的抽象的工厂接口
interface IFactory
{
IUser CreateUser();
IDepartment CreateDepartment(); //增加的接口方法
}
//SQLServerFactory类,实现IFactory接口,实例化SQLserverUser和SQLserverDepartment
class SqlServerFactory : IFactory
{
public IUser CreateUser()
{
return new SqlserverUser();
}
public IDepartment CreateDepartment() //增加了SQLserverDepartment工厂
{
return new sqlserverDepartment();
}
}
优点:
1、易于交换产品系列,由于具体工厂类在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。
2、让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。
缺点:
产品扩展非常困难,由于抽象工厂模式解决的是涉及到多个产品系列的问题,那么再进行产品扩展需要进行大批量的改动,所以有时候也要工厂家族的其他族员和反射等方法来对其改进。
小结
工厂家族虽然给编程带来了很多好处,各有其优点,但他们也各有其局限性,都不够灵活,设计模式的使用不是一成不变必须按套路来的,需要我们在实际情况中配合使用,从而做到面向对象,编程是门艺术,随着学习的不断深入,相信我们一定会达到炉火纯青,随手写出优美代码的程度的,fighting!!