抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而不需指定他们具体的类。
一、模式描述
我的程序中有需要一系列的对象,比如我们要吃一碗米饭(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
由于最近生病精神不振,文章介绍的不是很清楚,望大家体谅。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述