抽象工厂模式

前面我们介绍了简单工厂模式和工厂方法模式,现在简单的回顾一下:

简单工厂模式是充分利用面向对象的三大特性,将操作要素和操作方法对象化,通过定义工厂方法,决定实例化哪个对象。但简单工厂模式不利于程序的扩展,在需要扩展的时候需要将整个工程类开放,不符合开放-封闭原则。

在简单工厂模式的基础上,我们通过继承接口实现个操作对象的实例化,各具体操作类各自实现相应的方法,只需实现工厂类接口方法即可,在对功能进行扩展时,不需要对工厂类接口进行修改,只需新增操作类和实例化自己的工厂类即可。

那我们为什么需要抽象工厂模式呢?

当我们项目的数据库需要从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类的情况下更换数据库。

posted @ 2012-06-17 17:13  iskyoole  阅读(227)  评论(0编辑  收藏  举报