热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

基于.NET框架的分层架构实践(六):依赖注入与IoC容器的设计和实现详解

在基于.NET框架的分层架构实践中,为了实现各层之间的松散耦合,本文详细探讨了依赖注入(DI)和控制反转(IoC)容器的设计与实现。通过合理的依赖管理和对象创建,确保了各层之间的单向调用关系,从而提高了系统的可维护性和扩展性。此外,文章还介绍了几种常见的IoC容器实现方式及其应用场景,为开发者提供了实用的参考。

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

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

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

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

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

  上图以数据访问层为例,展示了Abstract Factory模式的应用。如图,现假设有针对Access和SQLServer两种数据库的 数据访问层,它们都实现了数据访问层接口。每个数据访问层有自己的工厂,所有工厂都实现自IDALFactory接口。而客户类(这里就是业务逻辑层类) 仅与工厂接口、数据访问层接口耦合,而与具体类无关,这样,只要通过配置文件确定实例化哪个工厂,就可以得到不同的数据访问层。

  然而,这种设计虽然可行,但是代码比较冗余,因为这样需要为数据访问层的每一个实现编写一个工厂,业务逻辑层也一样。在以前,我们毫无办法,但是,.net平台引入的反射机制,给我们提供了一种解决方案。使用反射,每个层只需要一个工厂,然后通过从配置文件中读出程序集的名称,动态加载相应类。另外,为了提高依赖注入机制的效率,这里引入缓存机制。下面来看具体实现。

一,配置

  首先,需要在Web工程的Web.config文件的节点下添加如下两个项:

  

  

  这两个配置选项分别存储要应用的数据访问和也业务逻辑层的程序集名称。value目前是空,是因为目前还没有各个层次的具体实现。

  实现缓存操作辅助类

  为实现缓存操作,我们将缓存操作封装成一个辅助类,放在Utility工程下,具体代码如下:

  CacheAccess.cs:

  CacheAccess

1using System;
2using System.Web;
3using System.Web.Caching;
4
5namespace NGuestBook.Utility
6{
7  /**//// 
8  /// 辅助类,用于缓存操作
9  /// 
10  public sealed class CacheAccess
11  {
12    /**//// 
13    /// 将对象加入到缓存中
14    /// 
15    /// 缓存键
16    /// 缓存对象
17    /// 缓存依赖项
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    /**//// 
25    /// 从缓存中取得对象,不存在则返回null
26    /// 
27    /// 缓存键
28    /// 获取的缓存对象
29    public static object GetFromCache(string cacheKey)
30    {
31      Cache cache = HttpRuntime.Cache;
32
33      return cache[cacheKey];
34    }
35  }
36}

 

二,封装依赖注入代码

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

  DependencyInjector.cs:

  DependencyInjector

1using System;
2using System.Configuration;
3using System.Reflection;
4using System.Web;
5using System.Web.Caching;
6using NGuestBook.Utility;
7
8namespace NGuestBook.Factory
9{
10  /**//// 
11  /// 依赖注入提供者
12  /// 使用反射机制实现
13  /// 
14  public sealed class DependencyInjector
15  {
16    /**//// 
17    /// 取得数据访问层对象
18    /// 首先检查缓存中是否存在,如果不存在,则利用反射机制返回对象
19    /// 
20    /// 数据访问类名称
21    /// 数据访问层对象
22    public static object GetDALObject(string className)
23    {
24      /**//// 
25      /// 取得数据访问层名称,首先检查缓存,不存在则到配置文件中读取
26      /// 缓存依赖项为Web.Config文件
27      /// 
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      /**//// 
37      /// 取得数据访问层对象
38      /// 
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    /**//// 
53    /// 取得业务逻辑层对象
54    /// 首先检查缓存中是否存在,如果不存在,则利用反射机制返回对象
55    /// 
56    /// 业务逻辑类名称
57    /// 业务逻辑层对象
58    public static object GetBLLObject(string className)
59    {
60      /**//// 
61      /// 取得业务逻辑层名称,首先检查缓存,不存在则到配置文件中读取
62      /// 缓存依赖项为Web.Config文件
63      /// 
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      /**//// 
73      /// 取得业务逻辑层对象
74      /// 
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

  DALFactory

1using System;
2using NGuestBook.IDAL;
3
4namespace NGuestBook.Factory
5{
6  /**//// 
7  /// 数据访问层工厂,用于获取相应的数据访问层对象
8  /// 使用Abstract Factory设计模式+Facace设计模式+反射机制+缓存机制设计
9  /// 
10  public sealed class DALFactory
11  {
12    /**//// 
13    /// 获取管理员数据访问层对象
14    /// 
15    /// 管理员数据访问层对象
16    public static IAdminDAL CreateAdminDAL()
17    {
18      return (IAdminDAL)DependencyInjector.GetDALObject("AdminDAL");
19    }
20
21    /**//// 
22    /// 获取留言数据访问层对象
23    /// 
24    /// 留言数据访问层对象
25    public static IMessageDAL CreateMessageDAL()
26    {
27      return (IMessageDAL)DependencyInjector.GetDALObject("MessageDAL");
28    }
29
30    /**//// 
31    /// 获取评论数据访问层对象
32    /// 
33    /// 评论数据访问层对象
34    public static ICommentDAL CreateCommentDAL()
35    {
36      return (ICommentDAL)DependencyInjector.GetDALObject("CommentDAL");
37    }
38  }
39}

 

BLLFactory.cs

  BLLFactory

1using System;
2using NGuestBook.IBLL;
3
4namespace NGuestBook.Factory
5{
6  /**//// 
7  /// 业务逻辑层工厂,用于获取相应的业务逻辑层对象
8  /// 使用Abstract Factory设计模式+Facace设计模式+反射机制+缓存机制设计
9  /// 
10  public sealed class BLLFactory
11  {
12    /**//// 
13    /// 获取管理员业务逻辑层对象
14    /// 
15    /// 管理员业务逻辑层对象
16    public static IAdminBLL CreateAdminBLL()
17    {
18      return (IAdminBLL)DependencyInjector.GetBLLObject("AdminBLL");
19    }
20
21    /**//// 
22    /// 获取留言业务逻辑层对象
23    /// 
24    /// 留言业务逻辑层对象
25    public static IMessageBLL CreateMessageBLL()
26    {
27      return (IMessageBLL)DependencyInjector.GetBLLObject("MessageBLL");
28    }
29
30    /**//// 
31    /// 获取评论业务逻辑层对象
32    /// 
33    /// 评论业务逻辑层对象
34    public static ICommentBLL CreateCommentBLL()
35    {
36      return (ICommentBLL)DependencyInjector.GetBLLObject("CommentBLL");
37    }
38  }
39}

 

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


推荐阅读
  • 本文深入解析了 Apache 配置文件 `httpd.conf` 和 `.htaccess` 的优化方法,探讨了如何通过合理配置提升服务器性能和安全性。文章详细介绍了这两个文件的关键参数及其作用,并提供了实际应用中的最佳实践,帮助读者更好地理解和运用 Apache 配置。 ... [详细]
  • 本文详细探讨了Java集合框架的使用方法及其性能特点。首先,通过关系图展示了集合接口之间的层次结构,如`Collection`接口作为对象集合的基础,其下分为`List`、`Set`和`Queue`等子接口。其中,`List`接口支持按插入顺序保存元素且允许重复,而`Set`接口则确保元素唯一性。此外,文章还深入分析了不同集合类在实际应用中的性能表现,为开发者选择合适的集合类型提供了参考依据。 ... [详细]
  • 当前,众多初创企业对全栈工程师的需求日益增长,但市场中却存在大量所谓的“伪全栈工程师”,尤其是那些仅掌握了Node.js技能的前端开发人员。本文旨在深入探讨全栈工程师在现代技术生态中的真实角色与价值,澄清对这一角色的误解,并强调真正的全栈工程师应具备全面的技术栈和综合解决问题的能力。 ... [详细]
  • 深入解析Tomcat:开发者的实用指南
    深入解析Tomcat:开发者的实用指南 ... [详细]
  • 全面解析:Hadoop技术栈中的Linux操作系统概览
    全面解析:Hadoop技术栈中的Linux操作系统概览 ... [详细]
  • Django框架下的对象关系映射(ORM)详解
    在Django框架中,对象关系映射(ORM)技术是解决面向对象编程与关系型数据库之间不兼容问题的关键工具。通过将数据库表结构映射到Python类,ORM使得开发者能够以面向对象的方式操作数据库,从而简化了数据访问和管理的复杂性。这种技术不仅提高了代码的可读性和可维护性,还增强了应用程序的灵活性和扩展性。 ... [详细]
  • ASP11:深入解析与应用展望本文详细探讨了 ASP11 中的 `AppRelativeTemplateSourceDirectory` 属性,该属性用于获取或设置包含控件的 Page 或 UserControl 对象的应用程序相对虚拟目录。此外,文章还介绍了 1.0 版本中的 Binding 机制,分析了其在实际开发中的应用和优化方法,为开发者提供了全面的技术指导。 ... [详细]
  • 本文深入探讨了ASP.NET中ViewState、Cookie和Session三种状态管理技术的区别与应用场景。ViewState主要用于保存页面控件的状态信息,确保在多次往返服务器过程中数据的一致性;Cookie则存储在客户端,适用于保存少量用户偏好设置等非敏感信息;而Session则在服务器端存储数据,适合处理需要跨页面保持的数据。文章详细分析了这三种技术的工作原理及其优缺点,并提供了实际应用中的最佳实践建议。 ... [详细]
  • 基于Node.js的高性能实时消息推送系统通过集成Socket.IO和Express框架,实现了高效的高并发消息转发功能。该系统能够支持大量用户同时在线,并确保消息的实时性和可靠性,适用于需要即时通信的应用场景。 ... [详细]
  • 本文推荐了六款高效的Java Web应用开发工具,并详细介绍了它们的实用功能。其中,分布式敏捷开发系统架构“zheng”项目,基于Spring、Spring MVC和MyBatis技术栈,提供了完整的分布式敏捷开发解决方案,支持快速构建高性能的企业级应用。此外,该工具还集成了多种中间件和服务,进一步提升了开发效率和系统的可维护性。 ... [详细]
  • 深入解析 Django 中用户模型的自定义方法与技巧 ... [详细]
  • 作为140字符的开创者,Twitter看似简单却异常复杂。其简洁之处在于仅用140个字符就能实现信息的高效传播,甚至在多次全球性事件中超越传统媒体的速度。然而,为了支持2亿用户的高效使用,其背后的技术架构和系统设计则极为复杂,涉及高并发处理、数据存储和实时传输等多个技术挑战。 ... [详细]
  • 在Spring与Ibatis集成的环境中,通过Spring AOP配置事务管理至服务层。当在一个服务方法中引入自定义多线程时,发现事务管理功能失效。若不使用多线程,事务管理则能正常工作。本文深入分析了这一现象背后的潜在风险,并探讨了可能的解决方案,以确保事务一致性和线程安全。 ... [详细]
  • 从用户转型为开发者:一场思维升级的旅程 | 专访 StarRocks Committer 周威
    从用户转变为开发者,不仅是一次角色的转换,更是一场深刻的思维升级之旅。本次专访中,StarRocks Committer 周威分享了他如何在这一过程中逐步提升技术能力与思维方式,为开源社区贡献自己的力量。 ... [详细]
  • Django新手指南:第三步——构建你的首个项目
    在本教程中,我们将引导你完成创建第一个Django应用的步骤。通过实际操作,你将逐步了解Django框架的核心概念和基本功能。从项目结构到视图和模板的实现,我们将详细介绍每个环节,帮助你快速上手并构建出一个功能完整的Web应用。 ... [详细]
author-avatar
洗吉精洗白菜_773
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有