转自: http://www.cnblogs.com/beniao/archive/2008/07/18/1167987.html
一、模式描述 我的程序中有需要一系列的对象,比如我们要吃一碗米饭(Rice),要喝一杯咖啡(Coffee)......,要想利用他们,我们就必须在程序中根据用户要求,然后一个个调用 new 操作符来生成他们,这样客户程序就要知道相应的类的信息,生成的代码显然不够灵活。那么我们可以在代码中不利用具体的类,而只是说明我们需要什么,然后就能够得到我们想要的对象呢? 这当然是可以的,根据GOF在《设计模式》一书里介绍,要创建对象这样的工作应该是属于创建型模式完成的。熟悉各种设计模式意图的朋友就会很快得出结论:“提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类”,至少“无需指定它们具体的类”符合我们的要求。OK,这就是抽象工厂模式的意图。 二、模式意图 提供一个创建一系列相关或相互依赖对象的接口,而不需指定他们具体的类。三、模式UML图: 四、模式参与者 抽象工厂(Abstract Factory)角色: 担任这个角色的是工厂方法模式的核心,它是与应用系统商业逻辑无关的。 具体工厂(Concrete Factory)角色: 这个角色直接在客户端的调用下创建产品的实例。这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的商业逻辑紧密相关的。 抽象产品(Abstract Product)角色: 担任这个角色的类是工厂方法模式所创建的对象的父类,或它们共同拥有的接口。 具体产品(Concrete Product)角色: 抽象工厂模式所创建的任何产品对象都是某一个具体产品类的实例。这是客户端最终需要的东西,其内部一定充满了应用系统的商业逻辑。五、模式与反射 利用设计模式可以使我们的代码更灵活,更容易扩展,更容易维护。各种面向对象的程序设计语言都提供了基本相同的机制:比如类、继承、派生、多态等等。但是又有各自的特色,C# 中的反射机制便是一个很重要的工具,好好地利用就可以在实际中发挥很大的作用。 反射是.NET Framework中的一个非常重要的特性。相信绝大多数的朋友都对其有所了解或是已经熟练的应用这项技术。我们需要根据需求去动态的创建一对象的实例,在程序设计中,通常我们会为了解耦合,把接口的实现对象写入配置文件,让工厂自己去一个特定的地方(配置文件)找他应该要实例化的对象(接口的实现对象),通过这样来实现“依赖注入(Dependency Injection)”。 本来“依赖注入”需要专门的IOC容器提供,比如Spring.net,Castle这类似的框架产品。而在抽象工厂模式的应用中显然没有这么麻烦,通常的实现就是使用.NET技术‘反射’就可以了。下面是反射的两种常见应用: 应用一: Activator.CreateInstance("类型"); 应用二: Assembly.Load("程序集名称").CreateInstance("命名空间.类名称");
六、抽象工厂的简单实现
Entity Code
1 namespace DesignPattern.AbstractFactory 2 { 3 public class User 4 { 5 private int _id; 6 public int Id 7 { 8 get { return _id; } 9 set { _id = value; } 10 }11 12 private string _name; 13 public string Name 14 { 15 get { return _name; } 16 set { _name = value; } 17 }18 19 private string _age; 20 public string Age 21 { 22 get { return _age; } 23 set { _age = value; } 24 }25 26 public User() 27 { } 28 29 public User( int id, string name, string age) 30 { 31 _id = id; 32 _name = name; 33 _age = age; 34 }35 }36 }37 ---------------------------------------------------------------------- 38 namespace DesignPattern.AbstractFactory 39 { 40 public class News 41 { 42 private int _id; 43 public int Id 44 { 45 get { return _id; } 46 set { _id = value; } 47 }48 49 private string _title; 50 public string Title 51 { 52 get { return _title; } 53 set { _title = value; } 54 }55 56 private string _context; 57 public string Context 58 { 59 get { return _context; } 60 set { _context = value; } 61 }62 63 private string _author; 64 public string Author 65 { 66 get { return _author; } 67 set { _author = value; } 68 }69 70 public News() 71 { } 72 73 public News( int id, string title, string context, string author) 74 { 75 _id = id; 76 _title = title; 77 _context = context; 78 _author = author; 79 }80 }81 }82
1
namespace
DesignPattern.AbstractFactory
2
{ 3 /**/ /// <summary> 4 /// 抽象产品角色 5 /// </summary> 6 public interface INews 7 { 8 void Insert(News news); 9 News QueryById(int newsId); 10 }11 12 /**/ /// <summary> 13 /// 具体产品角色 14 /// </summary> 15 public class NewsSql:INews 16 { 17 public void Insert(News news) 18 { 19 Console.WriteLine(" 插入新闻到SQL数据库 " ); 20 }21 22 public News QueryById( int newsId) 23 { 24 return new News( 1 , " Hello " , " Hello C#! " , " beniao " ); 25 }26 }27 28 /**/ /// <summary> 29 /// 具体产品角色 30 /// </summary> 31 public class NewsAccess : INews 32 { 33 public void Insert(News news) 34 { 35 Console.WriteLine(" 插入新闻到Access数据库 " ); 36 }37 38 public News QueryById( int newsId) 39 { 40 return new News( 1 , " Hello " , " Hello C#! " , " beniao " ); 41 }42 }43 }
1
namespace
DesignPattern.AbstractFactory
2
{ 3 /**/ /// <summary> 4 /// 抽象产品角色 5 /// </summary> 6 public interface IUser 7 { 8 void Insert(User user); 9 User QueryById(int userId); 10 }11 12 /**/ /// <summary> 13 /// 具体产品角色 14 /// </summary> 15 public class UserSql:IUser 16 { 17 public void Insert(User user) 18 { 19 Console.WriteLine(" Insert SQL OK! " ); 20 }21 22 public User QueryById( int userId) 23 { 24 return new User( 1 , " beniao " , " 22 " ); 25 }26 }27 28 /**/ /// <summary> 29 /// 具体产品角色 30 /// </summary> 31 public class UserAccess : IUser 32 { 33 public void Insert(User user) 34 { 35 Console.WriteLine(" Insert Access OK! " ); 36 }37 38 public User QueryById( int userId) 39 { 40 return new User( 2 , " beniao " , " 23 " ); 41 }42 }43 }
1
namespace
DesignPattern.AbstractFactory
2
{ 3 /**/ /// <summary> 4 /// 工厂角色(根据配置文件来确定创建何种对象) 5 /// </summary> 6 public class DataAccess 7 { 8 public static IUser CreateUser() 9 { 10 string obj = ConfigurationManager.AppSettings[ " usersql " ]; 11 return (IUser)Assembly.Load( " DesignPattern.AbstractFactory " ).CreateInstance(obj); 12 }13 14 public static INews CreateNews() 15 { 16 string obj = ConfigurationManager.AppSettings[ " newssql " ]; 17 return (INews)Assembly.Load( " DesignPattern.AbstractFactory " ).CreateInstance(obj); 18 }19 }20 *********************************************************************************** 21 /**/ /// <summary> 22 /// 如果根据GOF的定义及UML图,此为抽象工厂角色 23 /// </summary> 24 public class Factory 25 { 26 public virtual IUser CreateUser() 27 { 28 return null ; 29 }30 31 public virtual INews CreateNews() 32 { 33 return null ; 34 }35 }36 37 /**/ /// <summary> 38 /// 具体的工厂角色 39 /// </summary> 40 public class SqlFactory:Factory 41 { 42 public override IUser CreateUser() 43 { 44 string obj = ConfigurationManager.AppSettings[ " usersql " ]; 45 return (IUser)Assembly.Load( " DesignPattern.AbstractFactory " ).CreateInstance(obj); 46 }47 48 public override INews CreateNews() 49 { 50 string obj = ConfigurationManager.AppSettings[ " newssql " ]; 51 return (INews)Assembly.Load( " DesignPattern.AbstractFactory " ).CreateInstance(obj); 52 }53 }54 55 /**/ /// <summary> 56 /// 具体的工厂角色 57 /// </summary> 58 public class AccessFactory : Factory 59 { 60 public override IUser CreateUser() 61 { 62 string obj = ConfigurationManager.AppSettings[ " useracc " ]; 63 return (IUser)Assembly.Load( " DesignPattern.AbstractFactory " ).CreateInstance(obj); 64 }65 66 public override INews CreateNews() 67 { 68 string obj = ConfigurationManager.AppSettings[ " newsacc " ]; 69 return (INews)Assembly.Load( " DesignPattern.AbstractFactory " ).CreateInstance(obj); 70 } 71 }72 }
1
namespace
DesignPattern.AbstractFactory
2
{ 3 class Program 4 { 5 static void Main( string [] args) 6 { 7 IUser user = DataAccess.CreateUser(); 8 user.Insert(null ); 9 10 INews news = DataAccess.CreateNews(); 11 news.Insert(null ); 12 13 // ******************GOF************************ 14 15 Factory factory = new SqlFactory(); 16 factory.CreateNews().Insert(null ); 17 factory.CreateUser().Insert(null ); 18 19 factory = new AccessFactory(); 20 factory.CreateNews().Insert(null ); 21 factory.CreateUser().Insert(null ); 22 }23 }24 }
七、.NET 2.0中的抽象工厂模式 .NET 2.0相比.NET 1.1有很大的改进,就在ADO.NET上来说吧,提供了一套新的操作接口。下面我就简单的介绍下这套接口的设计,在System.Date下提供了IDbConnection 、IDbCommand 、IDbDataAdapter以及IDbTransaction这样一系列接口,通过ProviderFactory 来完成具体实现对象的创建,这里就是抽象工厂模式的一个应用。示意性代码:
1
public
IDbConnection CreateConnection()
2
{ 3 IDbConnection conn = null ; 4 try 5 { 6 conn = (IDbConnection)Activator.CreateInstance(_connectionTypes[( int )_provider]); 7 } 8 catch (TargetInvocationException e) 9 { 10 throw new Exception(e.Message); 11 }12 return conn; 13 }
14
15
public
IDbConnection CreateConnection(
string
connectionString)
16
{ 17 IDbConnection conn = null ; 18 object [] param = { connectionString } ; 19 try 20 { 21 conn = (IDbConnection)Activator.CreateInstance(_connectionTypes[( int )_provider], param); 22 }23 catch (TargetInvocationException e) 24 { 25 throw new Exception(e.Message); 26 }27 return conn; 28 }
在_connectionTypes数组里存放的是IDbConnection接口的具体实现类型,如下:
private
static
Type[] _connectionTypes
=
new
Type[]
{ typeof (OleDbConnection), typeof (SqlConnection) }
;
由于Command,DataAdapter等对象的代码都和上面很相似,这里就不作过多解释,我把代码贴到下面,有兴趣的看看:
ProviderFactory
1 using System; 2 using System.Data; 3 using System.Configuration; 4 using System.Web; 5 using System.Web.Security; 6 using System.Web.UI; 7 using System.Web.UI.WebControls; 8 using System.Web.UI.WebControls.WebParts; 9 using System.Web.UI.HtmlControls; 10 using System.Reflection; 11 using System.Data.OleDb; 12 using System.Data.SqlClient; 13 14 /**/ /// <summary> 15 /// ProviderFactory 的摘要说明 16 /// </summary> 17 public class ProviderFactory 18 { 19 /**/ /// <summary> 20 /// 私有构造器,伪单例。 21 /// 一个具体的工厂通常是一个单件(Singleton)。 22 /// </summary> 23 private ProviderFactory() 24 { 25 26 } 27 28 public ProviderFactory(ProviderType provider) 29 { 30 _provider = provider; 31 } 32 33 private static Type[] _connectionTypes = new Type[] { typeof (OleDbConnection), typeof (SqlConnection) } ; 34 private static Type[] _commandTypes = new Type[] { typeof (OleDbCommand), typeof (SqlCommand) } ; 35 private static Type[] _dataAdapterTypes = new Type[] { typeof (OleDbDataAdapter), typeof (SqlDataAdapter) } ; 36 private static Type[] _dataParameterTypes = new Type[] { typeof (OleDbParameter), typeof (SqlParameter) } ; 37 38 private ProviderType _provider; 39 public ProviderType Provider 40 { 41 get { return _provider; } 42 set { _provider = value; } 43 } 44 45 public IDbConnection CreateConnection() 46 { 47 IDbConnection conn = null ; 48 try 49 { 50 conn = (IDbConnection)Activator.CreateInstance(_connectionTypes[( int )_provider]); 51 } 52 catch (TargetInvocationException e) 53 { 54 throw new Exception(e.Message); 55 } 56 return conn; 57 } 58 59 public IDbConnection CreateConnection( string connectionString) 60 { 61 IDbConnection conn = null ; 62 object [] param = { connectionString } ; 63 try 64 { 65 conn = (IDbConnection)Activator.CreateInstance(_connectionTypes[( int )_provider], param); 66 } 67 catch (TargetInvocationException e) 68 { 69 throw new Exception(e.Message); 70 } 71 return conn; 72 } 73 74 public IDbCommand CreateCommand() 75 { 76 IDbCommand cmd = null ; 77 try 78 { 79 cmd = (IDbCommand)Activator.CreateInstance(_commandTypes[( int )_provider]); 80 } 81 catch (TargetInvocationException e) 82 { 83 throw new Exception(e.Message); 84 } 85 return cmd; 86 } 87 88 public IDbCommand CreateCommand( string cmdText) 89 { 90 IDbCommand cmd = null ; 91 object [] args = { cmdText } ; 92 try 93 { 94 cmd = (IDbCommand)Activator.CreateInstance(_commandTypes[( int )_provider], args); 95 } 96 catch (TargetInvocationException e) 97 { 98 throw new Exception(e.Message); 99 }100 return cmd; 101 }102 103 public IDbCommand CreateCommand( string cmdText, IDbConnection connection) 104 { 105 IDbCommand cmd = null ; 106 object [] args = { cmdText, connection } ; 107 try 108 { 109 cmd = (IDbCommand)Activator.CreateInstance(_commandTypes[( int )_provider], args); 110 }111 catch (TargetInvocationException e) 112 { 113 throw new Exception(e.Message); 114 }115 return cmd; 116 }117 118 public IDbCommand CreateCommand( string cmdText, IDbConnection connection, IDbTransaction transaction) 119 { 120 IDbCommand cmd = null ; 121 object [] args = { cmdText, connection, transaction } ; 122 try 123 { 124 cmd = (IDbCommand)Activator.CreateInstance(_commandTypes[( int )_provider], args); 125 }126 catch (TargetInvocationException e) 127 { 128 throw new Exception(e.Message); 129 }130 return cmd; 131 }132 133 public IDbDataAdapter CreateDataAdapter() 134 { 135 IDbDataAdapter da = null ; 136 try 137 { 138 da = (IDbDataAdapter)Activator.CreateInstance(_dataAdapterTypes[( int )_provider]); 139 }140 catch (TargetInvocationException e) 141 { 142 throw new SystemException(e.InnerException.Message, e.InnerException); 143 }144 return da; 145 }146 147 public IDbDataAdapter CreateDataAdapter(IDbCommand selectCommand) 148 { 149 IDbDataAdapter da = null ; 150 object [] args = { selectCommand } ; 151 try 152 { 153 da = (IDbDataAdapter)Activator.CreateInstance(_dataAdapterTypes[( int )_provider], args); 154 }155 catch (TargetInvocationException e) 156 { 157 throw new SystemException(e.InnerException.Message, e.InnerException); 158 }159 return da; 160 }161 162 public IDbDataAdapter CreateDataAdapter( string selectCommandText, IDbConnection selectConnection) 163 { 164 IDbDataAdapter da = null ; 165 object [] args = { selectCommandText, selectConnection } ; 166 try 167 { 168 da = (IDbDataAdapter)Activator.CreateInstance(_dataAdapterTypes[( int )_provider], args); 169 }170 catch (TargetInvocationException e) 171 { 172 throw new SystemException(e.InnerException.Message, e.InnerException); 173 }174 return da; 175 }176 177 public IDbDataAdapter CreateDataAdapter( string selectCommandText, string selectConnectionString) 178 { 179 IDbDataAdapter da = null ; 180 object [] args = { selectCommandText, selectConnectionString } ; 181 try 182 { 183 da = (IDbDataAdapter)Activator.CreateInstance(_dataAdapterTypes[( int )_provider], args); 184 }185 catch (TargetInvocationException e) 186 { 187 throw new SystemException(e.InnerException.Message, e.InnerException); 188 }189 return da; 190 }191 192 public IDbDataParameter CreateDataParameter() 193 { 194 IDbDataParameter param = null ; 195 try 196 { 197 param = (IDbDataParameter)Activator.CreateInstance(_dataParameterTypes[( int )_provider]); 198 }199 catch (TargetInvocationException e) 200 { 201 throw new SystemException(e.InnerException.Message, e.InnerException); 202 }203 return param; 204 }205 206 public IDbDataParameter CreateDataParameter( string parameterName, object value) 207 { 208 IDbDataParameter param = null ; 209 object [] args = { parameterName, value } ; 210 try 211 { 212 param = (IDbDataParameter)Activator.CreateInstance(_dataParameterTypes[( int )_provider], args); 213 }214 catch (TargetInvocationException e) 215 { 216 throw new SystemException(e.InnerException.Message, e.InnerException); 217 }218 return param; 219 }220 221 public IDbDataParameter CreateDataParameter( string parameterName, DbType dataType) 222 { 223 IDbDataParameter param = CreateDataParameter(); 224 if (param != null ) 225 { 226 param.ParameterName = parameterName; 227 param.DbType = dataType; 228 }229 return param; 230 }231 232 public IDbDataParameter CreateDataParameter( string parameterName, DbType dataType, int size) 233 { 234 IDbDataParameter param = CreateDataParameter(); 235 if (param != null ) 236 { 237 param.ParameterName = parameterName; 238 param.DbType = dataType; 239 param.Size = size; 240 }241 return param; 242 }243 244 public IDbDataParameter CreateDataParameter( string parameterName, DbType dataType, int size, string sourceColumn) 245 { 246 IDbDataParameter param = CreateDataParameter(); 247 if (param != null ) 248 { 249 param.ParameterName = parameterName; 250 param.DbType = dataType; 251 param.Size = size; 252 param.SourceColumn = sourceColumn; 253 }254 return param; 255 }256 }257
关于.NET 2.0的这一知识点不了解的朋友可以下载Web Cast课程进行学习。本文就简单的介绍这些。
七、.NET 2.0中的新ADO.NET操作接口应用示例 建立一ASP.NET网站项目,在默认的Default.aspx里放置一个GridView控件便OK。这里以MSSQL 2000里的Northwind数据库作为示例数据库,查询出订单表的数据呈现在aspx页面上, 进入后台代码文件(.cs文件):
1
public
partial
class
_Default : System.Web.UI.Page
2
{ 3 protected void Page_Load( object sender, EventArgs e) 4 { 5 string connectionString = " Data Source=.;Initial Catalog=Northwind;user id=sa;password=; " ; 6 string cmdText = " select * from orders " ; 7 8 ProviderFactory factory = new ProviderFactory(ProviderType.SqlClient); 9 IDbConnection conn = factory.CreateConnection(connectionString); 10 IDbDataAdapter sda = factory.CreateDataAdapter(cmdText, conn); 11 DataSet ds = new DataSet(); 12 sda.Fill(ds);13 this .GridView1.DataSource = ds.Tables[ 0 ]; 14 this .GridView1.DataBind(); 15 }16 }
ProviderFactory 担任着工厂的角色,负责创建如IDbConnection、IDbCommand等一系列的产品。如上,我们拿到了工厂角色,通过工厂角色的CreateConnection就创建到了一个基于抽象产品角色IDbConnection接口的实现对象(具体是什么实现对象我们暂不管)。 .NET 2.0提供了这一套操作接口,对于程序实现上就更加灵活了,更是强调了使用“依赖接口/抽象编程”的思想。 示例程序代码下载 注:转载请注明出处:http://beniao.cnblogs.com/ 或 http://www.cnblogs.com