设计模式(十一)抽象工厂模式

抽象工厂模式(Abstract Factory),提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

优点:

1、易于交换产品系列,由于具体工厂类,如 IFactory factory = new AccessFactory(),在一个应用中只需要在初始化时出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。

2、它让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。

 【例】数据访问程序

基本代码

  1 // IDepartment 接口,用于客户端访问,解除与具体数据库访问的耦合
  2 interface IDepartment
  3 {
  4   void Insert(Department department);
  5 
  6   Department GetDepartment(int id);
  7 }
  8 
  9 // SqlserverDepartment 类,用于访问 SQL Server 的 Department
 10 class SqlserverDepartment :  IDepartment
 11 {
 12   public void Insert(Department department)
 13   {
 14     Console.WriteLine("在 SQL Server 中给 Department 表增加一条记录");
 15   }
 16 
 17   public Department GetDepartment(int id)
 18   {
 19     Console.WriteLine("在 SQL Server 中根据 ID 得到 Department 表一条记录");
 20     return null;
 21   }
 22 }
 23 
 24 // AccessDepartment 类,用于访问 Access 的 Department
 25 class AccessDepartment :  IDepartment
 26 {
 27   public void Insert(Department department)
 28   {
 29     Console.WriteLine("在 Access 中给 Department 表增加一条记录");
 30   }
 31 
 32   public Department GetDepartment(int id)
 33   {
 34     Console.WriteLine("在 Access 中根据 ID 得到 Department 表一条记录");
 35     return null;
 36   }
 37 }
 38 
 39 // IUser 接口,用于客户端访问,解除与具体数据库访问的耦合
 40 interface IUser
 41 {
 42   void Insert(User user);
 43 
 44   User GetUser(int id);
 45 }
 46 
 47 // SqlserverUser 类,用于访问 SQL Server 的 User
 48 class SqlserverUser : IUser
 49 {
 50   public void Insert(User user)
 51   {
 52     Console.WriteLine("在 SQL Server 中给 User 表增加一条记录");
 53   }
 54 
 55   public User GetUser(int id)
 56   {
 57     Console.WriteLine("在 SQL Server 中根据 ID 得到 User 表一条记录");   
 58     return null;
 59   }
 60 }
 61 
 62 // AccessUser 类,用于访问 Access 的 User
 63 class AccessUser : IUser
 64 {
 65   public void Insert(User user)
 66   {
 67     Console.WriteLine("在 Access 中给 User 表增加一条记录");
 68   }
 69 
 70   public User GetUser(int id)
 71   {
 72     Console.WriteLine("在 Access 中根据 ID 得到 User 表一条记录");   
 73     return null;
 74   }
 75 }
 76 
 77 // IFactory 接口,定义一个创建访问 User 表对象的抽象的工厂接口
 78 interface IFactory
 79 {
 80   IUser CreateUser();
 81 
 82   IDepartment CreateDepartment();
 83 }
 84 
 85 // SqlServerFactory 类,实现 IFactory 接口,实例化 SqlserverUser 和 SqlserverDepartment
 86 class SqlServerFactory : IFactory
 87 {
 88   public IUser CreateUser()
 89   {
 90     return new SqlserverUser();
 91   }
 92 
 93   public IDepartment CreateDepartment()
 94   {
 95     return new SqlserverDepartment();
 96   }
 97 }
 98 
 99 // AccessFactory 类,实现 IFactory 接口,实例化 AccessUser 
100 class AccessFactory : IFactory
101 {
102   public IUser CreateUser()
103   {
104     return new AccessUser();
105   }
106 
107   public IDepartment CreateDepartment()
108   {
109     return new AccessDepartment();
110   }
111 }
112 
113 // 客户端
114 static void Main(string[] args)
115 {
116   //IFactory factory = new AccessFactory();
117   IFactory factory = new SqlServerFactory();
118 
119   User user = new User();
120   IUser iu = factory.CreateUser();
121   iu.Insert(user);
122   iu.GetUser(1);
123 
124   Department dept = new Department();
125   IDepartment id = factory.CreateDepartment();
126   id.Insert(dept);
127   id.GetDepartment(1);
128 
129   Console.Read();
130 }

 【改进的代码结构图】

基本代码

 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 }
36 
37 // 客户端
38 static void Main(string[] args)
39 {
40   User user = new User();
41   IUser iu = DataAccess.CreateUser();
42   iu.Insert(user);
43   iu.GetUser(1);
44 
45   Department dept = new Department();
46   IDepartment id = DataAccess.CreateDepartment();
47   id.Insert(dept);
48   id.GetDepartment(1);
49 
50   Console.Read();
51 }

 用【反射 + 抽象工厂】的数据访问程序

 1 // 引入反射
 2 using System.Reflection;  
 3 
 4 class DataAccess
 5 {
 6   // 程序集名称
 7   private static readonly string AssemblyName = "抽象工厂模式";
 8   // 数据库名称
 9   private static readonly string db = "Sqlserver";
10 
11   public static IUser CreateUser()
12   {
13     string className = AssemblyName + "." + db + "User";
14     return (IUser)Assembly.Load(AssemblyName).CreateInstance(className);
15   }
16 
17   public static IDepartment CreateDepartment()
18   {
19     string classname = AssemblyName + "." + db + "Department";
20     return (IDepartment)Assembly.Load(AssemblyName).CreateInstance(className);
21   }
22 }

  用【反射 + 配置文件】的数据访问程序

 1 // App.config
 2 <?xml version="1.0" encoding="utf-8" ?>
 3 <configuration>
 4   <appSettings>
 5     <add key="DB" value="Sqlserver"/>
 6   </appSettings>
 7 </configuration>
 8 
 9 using System.Configuration;
10 
11 // 读配资文件
12 private static readonly string db = ConfigurationManager.AppSetting["DB"];

【总结】

所有在用简单工厂的地方,都可以考虑用反射技术来去除 switch 或 if,解除分支判断带来的耦合。

posted @ 2015-06-19 11:33  壬子木  阅读(108)  评论(0)    收藏  举报