前面我们介绍了简单工厂模式和工厂方法模式,现在简单的回顾一下:
简单工厂模式是充分利用面向对象的三大特性,将操作要素和操作方法对象化,通过定义工厂方法,决定实例化哪个对象。但简单工厂模式不利于程序的扩展,在需要扩展的时候需要将整个工程类开放,不符合开放-封闭原则。
在简单工厂模式的基础上,我们通过继承接口实现个操作对象的实例化,各具体操作类各自实现相应的方法,只需实现工厂类接口方法即可,在对功能进行扩展时,不需要对工厂类接口进行修改,只需新增操作类和实例化自己的工厂类即可。
那我们为什么需要抽象工厂模式呢?
当我们项目的数据库需要从sqlserver改成oracle时,当初用抽象工厂模式设计的优点就体现出来了。
抽象工厂模式:创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

以数据访问为例:
1 interface IUser
2 {
3 void Insert(User user);
4
5 User GetUser(int id);
6 }
1 class SqlserverUser : IUser
2 {
3 public void Insert(User user)
4 {
5 Console.WriteLine("在Sqlserver中给User表增加一条记录");
6 }
7
8 public User GetUser(int id)
9 {
10 Console.WriteLine("在Sqlserver中根据ID得到User表一条记录");
11 return null;
12 }
13 }
14
15 class AccessUser : IUser
16 {
17 public void Insert(User user)
18 {
19 Console.WriteLine("在Access中给User表增加一条记录");
20 }
21
22 public User GetUser(int id)
23 {
24 Console.WriteLine("在Access中根据ID得到User表一条记录");
25 return null;
26 }
27 }
1 interface IFactory
2 {
3 IUser CreateUser();
4 }
5
6 class SqlServerFactory : IFactory
7 {
8 public IUser CreateUser()
9 {
10 return new SqlserverUser();
11 }
12 }
13
14 class AccessFactory : IFactory
15 {
16 public IUser CreateUser()
17 {
18 return new AccessUser();
19 }
20 }
客户端调用:
1 User user = new User(); //IFactory factory=new SqlServerFactory();//SqlServer调用 3 IFactory factory = new AccessFactory();//Access调用 4 5 IUser iu = factory.CreateUser(); 6 7 iu.Insert(user); 8 iu.GetUser(1); 9 10 Console.Read();
当我们新增了一个表时,我们至少要新增四个类:表对象类,表对应接口类,表对象操作在sqlserver类,表对象操作在access类;修改三个类:工厂接口类,工厂接口类在sqlserver中实现类,工厂接口类在access中实现类。
还有就是当我们更改数据库时,程序中所有对工厂类进行实例化的地方都要修改。为此,我们可以通过简单工厂来改进抽象工厂:
将工厂接口类,工厂接口类在sqlserver中实现类,工厂接口类在access中实现类融合到一个类,也就是说将数据访问判断从客户端移到统一类:
1 class DataAccess
2 {
3 private static readonly string db = "Sqlserver";
4 //private static readonly string db = "Access";
5
6 public static IUser CreateUser()
7 {
8 IUser result = null;
9 switch (db)
10 {
11 case "Sqlserver":
12 result = new SqlserverUser();
13 break;
14 case "Access":
15 result = new AccessUser();
16 break;
17 }
18 return result;
19 }
20
21 public static IDepartment CreateDepartment()
22 {
23 IDepartment result = null;
24 switch (db)
25 {
26 case "Sqlserver":
27 result = new SqlserverDepartment();
28 break;
29 case "Access":
30 result = new AccessDepartment();
31 break;
32 }
33 return result;
34 }
35 }
但现在又有新的问题:当我们需要增加oracle数据访问时,需要在dataaccess类中的每个方法新增switch。
为了解决这个问题,我们需要用到反射机制。
使用.net里面的system.Reflection实现反射:
1 class DataAccess
2 {
3 private static readonly string AssemblyName = "抽象工厂模式";//命名空间
4 private static readonly string db = "Sqlserver";//要实例化的类前缀
5 //private static readonly string db = "Access";
6
7 public static IUser CreateUser()
8 {
9 string className = AssemblyName + "." + db + "User";
10 return (IUser)Assembly.Load(AssemblyName).CreateInstance(className);
11 }
12
13 public static IDepartment CreateDepartment()
14 {
15 string className = AssemblyName + "." + db + "Department";
16 return (IDepartment)Assembly.Load(AssemblyName).CreateInstance(className);
17 }
18 }
当然为了在更换数据库时完全不修改程序,我们可以用配置文件代替,在程序中读取配置文件。
private static readonly string db = "Sqlserver";//要实例化的类前缀
这样我们就可以在不修改DataAccess类的情况下更换数据库。
来源:https://www.cnblogs.com/iskyoole/archive/2012/06/17/2552732.html