设计模式(十一)抽象工厂模式
抽象工厂模式(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,解除分支判断带来的耦合。