原文:http://www.cnblogs.com/leoo2sk/archive/2008/06/19/1225223.html

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

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

  在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:

  CacheAccess

1using System;
2using System.Web;
3using 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:

  DependencyInjector

1using System;
2using System.Configuration;
3using System.Reflection;
4using System.Web;
5using System.Web.Caching;
6using 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

  DALFactory

1using System;
2using 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

  BLLFactory

1using System;
2using 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");
    }
  }
}

 

基于.NET平台的分层架构实战(六)——依赖注入机制及IoC的设计与实现[转]的更多相关文章

  1. [.net 面向对象程序设计深入](26)实战设计模式——使用Ioc模式(控制反转或依赖注入)实现松散耦合设计(1)

    [.net 面向对象程序设计深入](26)实战设计模式——使用IoC模式(控制反转或依赖注入)实现松散耦合设计(1) 1,关于IOC模式 先看一些名词含义: IOC: Inversion of con ...

  2. [.net 面向对象程序设计深入](31)实战设计模式——使用Ioc模式(控制反转或依赖注入)实现松散耦合设计(1)

    [.net 面向对象程序设计深入](31)实战设计模式——使用IoC模式(控制反转或依赖注入)实现松散耦合设计(1) 1,关于IOC模式 先看一些名词含义: IOC: Inversion of con ...

  3. 基于LAMP平台的网站架构(或Web系统架构)

    1.网站架构的前提(或者说需求) 我们公司是一电子商务的网站,因为线下家具建材项目的推广需求,从而有了我们公司的这个线上网站,在这里我贴一张公司的网站架构图. 总体来说网站规模不是太大,注册人数在15 ...

  4. 基于SpringCloud的微服务架构实战案例项目,以一个简单的购物流程为示例

    QuickStart 基于SpringCloud体系实现,简单购物流程实现,满足基本功能:注册.登录.商品列表展示.商品详情展示.订单创建.详情查看.订单支付.库存更新等等. 每个业务服务采用独立的M ...

  5. 基于SpringCloud的微服务架构实战案例项目

    QuickStart 基于SpringCloud体系实现,简单购物流程实现,满足基本功能:注册.登录.商品列表展示.商品详情展示.订单创建.详情查看.订单支付.库存更新等等. github源码地址:h ...

  6. Spring 3.x企业应用开发实战(9-1)----依赖注入

    Spring中的依赖注入方式:属性注入.构造函数注入和工厂方式注入. 1.属性注入 属性注入即通过setXxx()方法注入Bean的属性值或依赖对象. 属性注入要求Bean提供一个默认的构造函数,在J ...

  7. Asp.Net Core 项目实战之权限管理系统(4) 依赖注入、仓储、服务的多项目分层实现

    0 Asp.Net Core 项目实战之权限管理系统(0) 无中生有 1 Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端 2 Asp.Net Core 项目实战之 ...

  8. 【转载】DDD分层架构的三种模式

    引言 在讨论DDD分层架构的模式之前,我们先一起回顾一下DDD和分层架构的相关知识. DDD DDD(Domain Driven Design,领域驱动设计)作为一种软件开发方法,它可以帮助我们设计高 ...

  9. DDD分层架构的三种模式

    引言 在讨论DDD分层架构的模式之前,我们先一起回顾一下DDD和分层架构的相关知识. DDD DDD(Domain Driven Design,领域驱动设计)作为一种软件开发方法,它可以帮助我们设计高 ...

随机推荐

  1. linux 列出安装包内的文件

    rpm系列: 1. 文件类型  rpm -qpl xxx.rpm2. 已安装文件  rpm -ql packagename debain系列: dpkg -c xxxx.deb

  2. 快速排序 javascript实现

    Quicksort(快速排序) 是由 东尼·霍尔 所发展的一种排序. 它比其他的Ο(n log n)算法更快, 因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来.当然, ...

  3. ajax的访问 WebService 的方法

    如果想用ajax进行访问 首先在web.config里进行设置 添加在 <webServices> <protocols> <add name= "HttpPo ...

  4. python3实现的web端json通信协议

    之前有用python3实现过tcp协议的,后来又实现了http协议的通信,今天公司想做一个功能自动测试系统, 下午弄了一会,发现json格式的实现可以更简单一点,代码如下:简单解说一下,一般与服务器通 ...

  5. input file 模拟预览图片。

    首先申明,接下来内容只是单纯的预览图片,最多选择九张,并没有和后台交互,交互的话需要自己另外写js. 本来想写一个调用摄像头的demo,意外的发现input file 在手机端打开的话,ios可以调用 ...

  6. [C#]async/Await 使用小计

    如果指定使用 异步 或 异步 修饰符,方法是异步方法,可以实现以下两个函数.  • 清单异步方法可以使用 Await 或指定的 等待 悬挂点.  等待运算符通知编译器异步方法不能继续点的过去,直到等待 ...

  7. 两个由于php.ini配置错误导致的报错:ajax图片上传报错和exec报错

    遇到了两个由于php.ini配置错误导致的报错:ajax图片上传报错和exec报错 首先第一个: 在做一个用ajax图片上传的功能中,php报了这样一个错误:File upload error - u ...

  8. MySQL簇-cluster

    http://www.php100.com/manual/MySQL/ndbcluster.html 先做个标记吧.

  9. letcode刷题之两数相加

    letcode里面刷题,坑还是链表不熟,(1)头结点还是有必要设置,否则返回的时候找不到位置:(2)先设置next到新节点再next到下一个节点:都是基础知识 /* * * You are given ...

  10. PCB设计之原理图绘制笔记

    02原理图工作环境设置原理图画布由画布和边界(Border)构成.可以通过DocumentOptions设置(快捷键DO).DocumentOptions设置--------------------- ...