简单工厂、工厂方法和抽象工厂这三种设计模式都和工厂有关,准确的来说都和对象的创建有关。它们之间有什么区别呢?我认为就是一个逐步改进的过程。
简单工厂
不论创建哪个对象,都封装在一个简单工厂类中,一对多
优点:将客户端与对象的创建(选择创建哪个对象)分离,去除了客户端对具体产品的依赖
缺点:违背了开闭原则,增加新的类就需要修改简单工厂类,而不是可扩展
工厂方法
将创建对象的工厂抽象出来,为每一个需要实例化的类都开辟一个具体的工厂类,一对一
优点:既解决了简单工厂违背了开闭原则的缺点,但是每增加一个产品,就要增加一个具体的产品工厂类,又保持了实例化对象封装的特点
缺点:将判断(创建哪个对象)移到了客户端,更改要实例化的对象时需要修改客户端
抽象工厂
优点:①易于交换系列产品 ②让具体的创建实例过程和客户端分离,客户端是通过抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在代码中。遵循了开闭原则和依赖倒置原则。
缺点:如果要增加产品,需要修改抽象工厂类和具体工厂类
适用情况:解决涉及到多个产品系列的问题,用于系列产品之间的交换,比如访问不同的数据库
改进:用【简单工厂+反射】改进抽象工厂,去除抽象工厂类和具体工厂类
简单工厂和工厂方法的区别
①工厂方法和简单工厂比较,将工厂类也抽象出来,有接口工厂和具体工厂
②工厂方法运用了依赖倒置原则,针对接口编程而不是针对实现编程
③简单工厂在程序编译时就已经确定了实例化哪个对象,而工厂方法将程序编译时转为运行时,由于客户端运用的是接口工厂,所以在运行时才知道具体实例化运行哪一个对象。
具体看下图:
1)简单工厂
2)工厂方法
工厂方法和抽象工厂
我认为工厂方法和抽象工厂基本上没有什么区别,只是增加了多个系列类而已,而且工厂类中创建对象的方法也增多了。
利用反射改进抽象工厂
对抽象工厂的进一步改进,可以用一个简单工厂类替换掉抽象工厂类和具体工厂类,不过在简单工厂类中不再用 switch 语句选择创建对象,而是利用反射技术。
反射技术的格式为:
Assembly.Load("程序集名称").CreateInstance("命名空间.类名")
使用示例:
//使用之前需要先引用
using System.Reflection;
using System.Configuration;
namespace _04抽象工厂模式
{
class DataAccess
{
//程序集名称
private static readonly string AssemblyName = "04抽象工厂模式";
private static readonly string db = "Sqlserver";
public static IUser CreateUser()
{
//命名空间.类名
string className = "_" + AssemblyName + "." + db + "User";
return (IUser)Assembly.Load(AssemblyName).CreateInstance(className);
}
public static IDepartment CreateDepartment()
{
string className = "_" + AssemblyName + "." + db + "Department";
return (IDepartment)Assembly.Load(AssemblyName).CreateInstance(className);
}
}
}
注意:
①一个项目就是一个程序集,准确的说程序集就是编译后的.exe文件或.dll文件,但程序集名称可以和项目名称不同,可以右键项目属性查看程序集名称。
②命名空间:
namespace _04抽象工厂模式 //这就是命名空间的名称
一个项目可以有不同的命名空间,但是一般都用相同的命名空间。
③所有在用简单工厂的地方,都可以用反射技术来去除 switch。