基于.NET平台的分层架构实战(六)——依赖注入机制及IoC的设计与实现
之所以这样做,是为了实现层与层之间的“可替换”式设计,例如,现在需要换一种方式实现数据访问层,只要这个实现遵循了前面定义的数据访问层接口,业务逻 辑层和表示层不需要做任何改动,只需要改一下配置文件系统即可正常运行。另外,基于这种结构的系统,还可以实现并行开发。即不同开发人员可以专注于自己的 层次,只有接口被定义好了,开发出来的东西就可以无缝连接。
在J2EE平台上,主要使用Spring框架实现依赖注入。这里,我们将自己做一个依赖注入容器。
依赖注入的理论基础是Abstract Factory设计模式,这里结合具体实例简单介绍一下。

上图以数据访问层为例,展示了Abstract Factory模式的应用。如图,现假设有针对Access和SQLServer两种数据库的数据访问层,它们都实现了数据访问层接口。每个数据访问层有 自己的工厂,所有工厂都实现自IDALFactory接口。而客户类(这里就是业务逻辑层类)仅与工厂接口、数据访问层接口耦合,而与具体类无关,这样, 只要通过配置文件确定实例化哪个工厂,就可以得到不同的数据访问层。
然而,这种设计虽然可行,但是代码比较冗余,因为这样需要为数据访问层的每一个实现编写一个工厂,业务逻辑层也一样。在以前,我们毫无办法,但 是,.NET平台引入的反射机制,给我们提供了一种解决方案。使用反射,每个层只需要一个工厂,然后通过从配置文件中读出程序集的名称,动态加载相应类。 另外,为了提高依赖注入机制的效率,这里引入缓存机制。下面来看具体实现。
配置
首先,需要在Web工程的Web.config文件的<appSettings>节点下添加如下两个项:
<add key="DAL" value=""/>
<add key="BLL" value=""/>
这两个配置选项分别存储要应用的数据访问和也业务逻辑层的程序集名称。value目前是空,是因为目前还没有各个层次的具体实现。
实现缓存操作辅助类
为实现缓存操作,我们将缓存操作封装成一个辅助类,放在Utility工程下,具体代码如下:
CacheAccess.cs:
using System;2
using System.Web;3
using System.Web.Caching;4

5
namespace NGuestBook.Utility6
{7
/// <summary>8
/// 辅助类,用于缓存操作9
/// </summary>10
public sealed class CacheAccess11
{12
/// <summary>13
/// 将对象加入到缓存中14
/// </summary>15
/// <param name="cacheKey">缓存键</param>16
/// <param name="cacheObject">缓存对象</param>17
/// <param name="dependency">缓存依赖项</param>18
public static void SaveToCache(string cacheKey, object cacheObject, CacheDependency dependency)19
{20
Cache cache = HttpRuntime.Cache;21
cache.Insert(cacheKey, cacheObject, dependency);22
}23

24
/// <summary>25
/// 从缓存中取得对象,不存在则返回null26
/// </summary>27
/// <param name="cacheKey">缓存键</param>28
/// <returns>获取的缓存对象</returns>29
public static object GetFromCache(string cacheKey)30
{31
Cache cache = HttpRuntime.Cache;32

33
return cache[cacheKey];34
}35
}36
}封装依赖注入代码
因为很多依赖注入代码非常相似,为了减少重复性代码,我们将可复用的代码先封装在一个类中。具体代码如下(这个类放在Factory工程下):
DependencyInjector.cs:
using System;2
using System.Configuration;3
using System.Reflection;4
using System.Web;5
using System.Web.Caching;6
using NGuestBook.Utility;7

8
namespace NGuestBook.Factory9
{10
/// <summary>11
/// 依赖注入提供者12
/// 使用反射机制实现13
/// </summary>14
public sealed class DependencyInjector15
{16
/// <summary>17
/// 取得数据访问层对象18
/// 首先检查缓存中是否存在,如果不存在,则利用反射机制返回对象19
/// </summary>20
/// <param name="className">数据访问类名称</param>21
/// <returns>数据访问层对象</returns>22
public static object GetDALObject(string className)23
{24
/// <summary>25
/// 取得数据访问层名称,首先检查缓存,不存在则到配置文件中读取26
/// 缓存依赖项为Web.Config文件27
/// </summary>28
object dal = CacheAccess.GetFromCache("DAL");29
if (dal == null)30
{31
CacheDependency fileDependency = new CacheDependency(HttpContext.Current.Server.MapPath("Web.Config"));32
dal = ConfigurationManager.AppSettings["DAL"];33
CacheAccess.SaveToCache("DAL", dal, fileDependency);34
}35

36
/// <summary>37
/// 取得数据访问层对象38
/// </summary>39
string dalName = (string)dal;40
string fullClassName = dalName + "." + className;41
object dalObject = CacheAccess.GetFromCache(className);42
if (dalObject == null)43
{44
CacheDependency fileDependency = new CacheDependency(HttpContext.Current.Server.MapPath("Web.Config"));45
dalObject = Assembly.Load(dalName).CreateInstance(fullClassName);46
CacheAccess.SaveToCache(className, dalObject, fileDependency);47
}48

49
return dalObject;50
}51

52
/// <summary>53
/// 取得业务逻辑层对象54
/// 首先检查缓存中是否存在,如果不存在,则利用反射机制返回对象55
/// </summary>56
/// <param name="className">业务逻辑类名称</param>57
/// <returns>业务逻辑层对象</returns>58
public static object GetBLLObject(string className)59
{60
/// <summary>61
/// 取得业务逻辑层名称,首先检查缓存,不存在则到配置文件中读取62
/// 缓存依赖项为Web.Config文件63
/// </summary>64
object bll = CacheAccess.GetFromCache("BLL");65
if (bll == null)66
{67
CacheDependency fileDependency = new CacheDependency(HttpContext.Current.Server.MapPath("Web.Config"));68
bll = ConfigurationManager.AppSettings["BLL"];69
CacheAccess.SaveToCache("BLL", bll, fileDependency);70
}71

72
/// <summary>73
/// 取得业务逻辑层对象74
/// </summary>75
string bllName = (string)bll;76
string fullClassName = bllName + "." + className;77
object bllObject = CacheAccess.GetFromCache(className);78
if (bllObject == null)79
{80
CacheDependency fileDependency = new CacheDependency(HttpContext.Current.Server.MapPath("Web.Config"));81
bllObject = Assembly.Load(bllName).CreateInstance(fullClassName);82
CacheAccess.SaveToCache(className, bllObject, fileDependency);83
}84

85
return bllObject;86
}87
}88
}
实现工厂
下面使用两个辅助类,实现数据访问层工厂和业务逻辑层工厂。
DALFactory.cs
using System;2
using NGuestBook.IDAL;3

4
namespace NGuestBook.Factory5
{6
/// <summary>7
/// 数据访问层工厂,用于获取相应的数据访问层对象8
/// 使用Abstract Factory设计模式+Facace设计模式+反射机制+缓存机制设计9
/// </summary>10
public sealed class DALFactory11
{12
/// <summary>13
/// 获取管理员数据访问层对象14
/// </summary>15
/// <returns>管理员数据访问层对象</returns>16
public static IAdminDAL CreateAdminDAL()17
{18
return (IAdminDAL)DependencyInjector.GetDALObject("AdminDAL");19
}20

21
/// <summary>22
/// 获取留言数据访问层对象23
/// </summary>24
/// <returns>留言数据访问层对象</returns>25
public static IMessageDAL CreateMessageDAL()26
{27
return (IMessageDAL)DependencyInjector.GetDALObject("MessageDAL");28
}29

30
/// <summary>31
/// 获取评论数据访问层对象32
/// </summary>33
/// <returns>评论数据访问层对象</returns>34
public static ICommentDAL CreateCommentDAL()35
{36
return (ICommentDAL)DependencyInjector.GetDALObject("CommentDAL");37
}38
}39
}
BLLFactory.cs


浙公网安备 33010602011771号