基于.NET平台的分层架构实战(六)——依赖注入机制及IoC的设计与实现

我们设计的分层架构,层与层之间应该是松散耦合的。因为是单向单一调用,所以,这里的“松散耦合”实际是指上层类不能具体依赖于下层类,而应该依赖于下层提供的一个接口。这样,上层类不能直接实例化下层中的类,而只持有接口,至于接口所指变量最终究竟是哪一个类,则由依赖注入机制决定。

之所以这样做,是为了实现层与层之间的“可替换”式设计,例如,现在需要换一种方式实现数据访问层,只要这个实现遵循了前面定义的数据访问层接口,业务逻辑层和表示层不需要做任何改动,只需要改一下配置文件系统即可正常运行。另外,基于这种结构的系统,还可以实现并行开发。即不同开发人员可以专注于自己的层次,只有接口被定义好了,开发出来的东西就可以无缝连接。

在J2EE平台上,主要使用Spring框架实现依赖注入。这里,我们将自己做一个依赖注入容器。

依赖注入的理论基础是Abstract Factory设计模式,这里结合具体实例简单介绍一下。

图6.1、Abtract 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;
using  System.Web;
using  System.Web.Caching;

namespace  NGuestBook.Utility
{
    
///   <summary>
    
///  辅助类,用于缓存操作
    
///   </summary>
     public   sealed   class  CacheAccess
    {
        
///   <summary>
        
///  将对象加入到缓存中
        
///   </summary>
        
///   <param name="cacheKey"> 缓存键 </param>
        
///   <param name="cacheObject"> 缓存对象 </param>
        
///   <param name="dependency"> 缓存依赖项 </param>
         public   static   void  SaveToCache( string  cacheKey,  object  cacheObject, CacheDependency dependency)
        {
            Cache cache 
=  HttpRuntime.Cache;
            cache.Insert(cacheKey, cacheObject, dependency);
        }

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

            
return  cache[cacheKey];
        }
    }
}


封装依赖注入代码
因为很多依赖注入代码非常相似,为了减少重复性代码,我们将可复用的代码先封装在一个类中。具体代码如下(这个类放在Factory工程下):

DependencyInjector.cs:

using  System;
using  System.Configuration;
using  System.Reflection;
using  System.Web;
using  System.Web.Caching;
using  NGuestBook.Utility;

namespace  NGuestBook.Factory
{
    
///   <summary>
    
///  依赖注入提供者
    
///  使用反射机制实现
    
///   </summary>
     public   sealed   class  DependencyInjector
    {
        
///   <summary>
        
///  取得数据访问层对象
        
///  首先检查缓存中是否存在,如果不存在,则利用反射机制返回对象
        
///   </summary>
        
///   <param name="className"> 数据访问类名称 </param>
        
///   <returns> 数据访问层对象 </returns>
         public   static   object  GetDALObject( string  className)
        {
            
///   <summary>
            
///  取得数据访问层名称,首先检查缓存,不存在则到配置文件中读取
            
///  缓存依赖项为Web.Config文件
            
///   </summary>
             object  dal  =  CacheAccess.GetFromCache( " DAL " );
            
if  (dal  ==   null )
            {
                CacheDependency fileDependency 
=   new  CacheDependency(HttpContext.Current.Server.MapPath( " Web.Config " ));
                dal 
=  ConfigurationManager.AppSettings[ " DAL " ];
                CacheAccess.SaveToCache(
" DAL " , dal, fileDependency);
            }

            
///   <summary>
            
///  取得数据访问层对象
            
///   </summary>
             string  dalName  =  ( string )dal;
            
string  fullClassName  =  dalName  +   " . "   +  className;
            
object  dalObject  =  CacheAccess.GetFromCache(className);
            
if  (dalObject  ==   null )
            {
                CacheDependency fileDependency 
=   new  CacheDependency(HttpContext.Current.Server.MapPath( " Web.Config " ));
                dalObject 
=  Assembly.Load(dalName).CreateInstance(fullClassName);
                CacheAccess.SaveToCache(className, dalObject, fileDependency);
            }

            
return  dalObject;
        }

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

            
///   <summary>
            
///  取得业务逻辑层对象
            
///   </summary>
             string  bllName  =  ( string )bll;
            
string  fullClassName  =  bllName  +   " . "   +  className;
            
object  bllObject  =  CacheAccess.GetFromCache(className);
            
if  (bllObject  ==   null )
            {
                CacheDependency fileDependency 
=   new  CacheDependency(HttpContext.Current.Server.MapPath( " Web.Config " ));
                bllObject 
=  Assembly.Load(bllName).CreateInstance(fullClassName);
                CacheAccess.SaveToCache(className, bllObject, fileDependency);
            }

            
return  bllObject;
        }
    }
}


实现工厂
下面使用两个辅助类,实现数据访问层工厂和业务逻辑层工厂。

DALFactory.cs

using  System;
using  NGuestBook.IDAL;

namespace  NGuestBook.Factory
{
    
///   <summary>
    
///  数据访问层工厂,用于获取相应的数据访问层对象
    
///  使用Abstract Factory设计模式+Facace设计模式+反射机制+缓存机制设计
    
///   </summary>
     public   sealed   class  DALFactory
    {
        
///   <summary>
        
///  获取管理员数据访问层对象
        
///   </summary>
        
///   <returns> 管理员数据访问层对象 </returns>
         public   static  IAdminDAL CreateAdminDAL()
        {
            
return  (IAdminDAL)DependencyInjector.GetDALObject( " AdminDAL " );
        }

        
///   <summary>
        
///  获取留言数据访问层对象
        
///   </summary>
        
///   <returns> 留言数据访问层对象 </returns>
         public   static  IMessageDAL CreateMessageDAL()
        {
            
return  (IMessageDAL)DependencyInjector.GetDALObject( " MessageDAL " );
        }

        
///   <summary>
        
///  获取评论数据访问层对象
        
///   </summary>
        
///   <returns> 评论数据访问层对象 </returns>
         public   static  ICommentDAL CreateCommentDAL()
        {
            
return  (ICommentDAL)DependencyInjector.GetDALObject( " CommentDAL " );
        }
    }
}


BLLFactory.cs

using  System;
using  NGuestBook.IBLL;

namespace  NGuestBook.Factory
{
    
/**/ ///   <summary>
    
///  业务逻辑层工厂,用于获取相应的业务逻辑层对象
    
///  使用Abstract Factory设计模式+Facace设计模式+反射机制+缓存机制设计
    
///   </summary>
     public   sealed   class  BLLFactory
    {
        
/**/ ///   <summary>
        
///  获取管理员业务逻辑层对象
        
///   </summary>
        
///   <returns> 管理员业务逻辑层对象 </returns>
         public   static  IAdminBLL CreateAdminBLL()
        {
            
return  (IAdminBLL)DependencyInjector.GetBLLObject( " AdminBLL " );
        }

        
/**/ ///   <summary>
        
///  获取留言业务逻辑层对象
        
///   </summary>
        
///   <returns> 留言业务逻辑层对象 </returns>
         public   static  IMessageBLL CreateMessageBLL()
        {
            
return  (IMessageBLL)DependencyInjector.GetBLLObject( " MessageBLL " );
        }

        
/**/ ///   <summary>
        
///  获取评论业务逻辑层对象
        
///   </summary>
        
///   <returns> 评论业务逻辑层对象 </returns>
         public   static  ICommentBLL CreateCommentBLL()
        {
            
return  (ICommentBLL)DependencyInjector.GetBLLObject( " CommentBLL " );
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值