3.3 建立松耦合组件(MVC 模式最重要的特性之一是它支持、关注“分离”)《精通 ASP.NET MVC 5》 推荐指数:8 星半
笔者通常希望应用程序中的组件尽可能独立,而只有很少几个可控的依赖项。—— 在理想情况下,每个组件都不了解其他组件,而只是通过抽象接口来处理应用程序的其他区域。这称为松耦合 。—— 它能够使应用程序更易于测试和修改。
当我们需要编写或者引用一个组件来实现一系列功能时(比如编写一个名称为“MyEmailSender”的组件,用以发送邮件信息),我们可以定义一个接口,它包含了发送邮件所需的所有 public 函数(这个接口可以命名为 “IEmailSender”)。
(IEmailSender 是一个接口,MyEmailSender 是该接口的一个具体实现类)
应用程序中任何需要发送电子邮件的部分(即“应用场景”,比如名称为 “PasswordResetHelper” 的“密码重置辅助程序”),只要通过引用该接口中的方法便可以发送一份邮件。
通过引入 IEmailSender,保证了 PasswordResetHelper 与 MyEmailSender 之间没有直接的依赖项。
这样的好处是,笔者完全可以用另一个邮件发送程序来替换 MyEmailSender,甚至用一个模仿实现以进行测试,而无须对 PasswordResetHelper 做任何修改。
3.3.1 使用依赖项注入
接口有助于解除组件耦合,但这里仍面临一个问题:
PasswordResetHelper 类要通过 IEmailSender 接口来配置并发送电子邮件,总归需要创建一个实现该接口的对象(必须创建一个 MyEmailSender 的实例)。但 C# 并未提供内置的方法以方便地创建实现接口的对象,除非以 new 关键字创建一个具体组件的实例。于是,代码如下:
public class PasswordResetHelper
{
public void ResetPassword()
{
IEmailSender mySender = new MyEmailSender();
//调用接口方法,以配置 email 细节
mySender.SendEmail();
}
}
这破坏了无须修改 PasswordResetHelper 就能替换 MyEmailSender 的目的,这意味着此刻仅处于组件松耦合的半途。
现在需要有一种办法,它能够获取实现某接口的对象,而不必直接创建该对象。—— 这一问题的解决方法称为依赖项注入(DI),也称为控制反转(IoC)。
DI 是一种实现组件解耦的设计模式。(也是有效从事 MVC 开发的一个重要概念。同时,DI 也可能会造成很多困惑)
DI 模式有两个部分:
1. 打断和声明依赖项
第一个部分是从组件(此例中的 PasswordResetHelper)中去除掉对具体类的依赖项。其做法是创建一个以所需接口的实现作为其参数的类构造器(构造方法)。如下所示:
public class PasswordResetHelper
{
private IEmailSender emailSender ; public PasswordResetHelper (IEmailSender emailSenderParam)
{
emailSender = emailSenderParam ;
} public void ResetPassword ()
{
emailSender.SendEmail();
}
}
现在可以将 PasswordResetHelper 类的构造器(构造方法)称为对 IEmailSender 接口声明了一个依赖项。
(除非接受一个实现了 IEmailSender 接口的对象,否则便不能创建和使用它 —— PasswordResetHelper 类)
在依赖项声明中,PasswordResetHelper 类不再有 MyEmailSender 的任何知识,它仅仅依赖于 IEmailSender 接口。简言之,PasswordResetHelper 不再了解或关心如何实现 IEmailSender 接口。
2. 注射依赖项
DI 模式的第二个部分是在创建 PasswordResetHelper 类的实例时,注入由其声明的依赖项。(即,在调用 PasswordResetHelper 的构造方法创建 PasswordResetHelper 类的实例时,把依赖项 —— MyEmailSender 的实例放进 PasswordResetHelper 的构造方法的参数里面去)。故称为依赖项注入。
(其实这也很好理解:第一步你要声明说这里需要放一个什么,那么第二步当然就是把它放进去啦!)—— 这种依赖项是在运行时处理的。
上述 PasswordResetHelper 类是通过构造器(构造方法/构造函数)来声明其依赖项的,这称为 “构造器注入”。
也可以通过一个 public 属性来声明要注入的依赖项,这称为 “设置器注入”,意即在该属性的 set 代码块中声明依赖项。
3.2.2 使用依赖项注入容器
至此已解决了依赖项问题,但按照现在的情况,在应用程序的某个地方仍然需要以下这些语句。
IEmailSender sender = new MyEmailSender();
helper = new PasswordResetHelper(sender);
如何在无须在应用程序的某个其他地方创建依赖项而对接口的具体实现进行实例化呢? —— 答案是使用 “依赖项注入容器(简称 DI 容器)”。
DI 容器是一种组件,它在类所声明的依赖项和用来解决这些依赖项的类( PasswordResetHelper 和 MyEmailSender )之间充当着中间件的角色。
可以用这种 DI 容器注册一组应用程序要使用的接口或抽象类型,并指明满足依赖项所需实例化的实现类。
因此在上例中,便会用 DI 容器注册 IEmailSender 接口,并指明在需要实例化 IEmailSender 时,应该创建一个 MyEmailSender 的实例。
(这里讲的就是第二步 —— 依赖项注入,所以重点在 IEmailSender 和 MyEmailSender )
当应用程序中需要一个 PasswordResetHelper 对象时,便要求 DI 容器去创建一个。
DI 容器知道 PasswordResetHelper 已经声明了一个关于 IEmailSender 接口的依赖项,而且知道已经将 MyEmailSender 类指定为用于该接口的实现。
DI 容器会将这两项信息结合在一起,从而创建 MyEmailSender 对象,然后用它作为创建 PasswordResetHelper 对象的一个参数,于是在应用程序中便可以使用这个 MyEmailSender 了。
重要的是要注意到:应用程序中已经不需要自己动手使用 new 关键字去创建这种对象了,而是进入 DI 容器请求所需的对象)
(DI 新手可能还需要一段时间去适应,但后面会看到,MVC 框架提供了一些特性,可以使该过程更加简单)
我们不需要自己去编写 DI 容器,有一些很棒的开源代码和免费的许可实现是可用的。
笔者所喜欢的并在自己的项目中使用的叫做 Ninject,可以在 http://www.ninject.org 上获得其细节。(第 6 章将介绍 Ninject 的使用,并演示如何用 NuGet 安装这个包)
微软公司创建了自己的 DI容器,叫做 Unity .(如果需要了解更多关于 Unity 的信息,可参阅 unity.codeplex.com)
DI 容器的作用似乎简单而平常,但事实并非如此。—— 一个好的 DI 容器,如 Ninject,有一些聪明的特性。
1、依赖链解析:
如果 MyEmailSender 类的构造器需要一个 INetworkTransport 接口的实现,DI 容器将实例化这个接口的默认实现,把它传递给 MyEmailSender 的构造器,并将返回结果作为 IEmailSender 的默认实现。)
2、对象生命周期管理:
一个好的 DI 容器能让你配置组件的生命周期,允许你从预定义的选项中进行选择。这些选项包括……(但是这里并没有介绍为什么要进行这个设置)
3、构造器参数值的配置:
如果 INetworkTransport 接口实现的构造器需要一个叫做 serverName 的字符串,你应该能够在 DI 容器的配置中为其设置一个值。
这是一种笨拙但简单的配置系统,它不需要你的代码传递诸如连接字符串、服务器地址等参数。
最后,编写自己的 DI 容器是理解 C# 和 .NET 如何处理类型及反射的一种很好的方式,而且建议将其作为闲暇而无事可做时的一个好项目。
但切不要试图在一个实际的项目中部署你写的这些代码。—— 编写可靠、健壮且高性能的 DI 容器是困难的,你应该找一个已经过验证且测试过的包来使用。
3.3 建立松耦合组件(MVC 模式最重要的特性之一是它支持、关注“分离”)《精通 ASP.NET MVC 5》 推荐指数:8 星半的更多相关文章
- Prism 4 文档 ---第9章 松耦合组件之间通信
当构建一个大而负责的应用程序时,通用的做法时将功能拆分到离散的模块程序集中.将模块之间的静态引用最小化.这使得模块可以被独立的开发,测试,部署和升级,以及它迫使松散耦合的沟通. 当在模块之间通信时,你 ...
- 3.4 自动测试初步《精通ASP.NET MVC 5》
概述 ASP.NET MVC 框架已被设计成易于建立自动测试,并易于采用诸如测试驱动开发(TDD)等的开发方法学.ASP.NET MVC 为自动化测试提供了一个理想平台. 从广义上讲,当今的 Web ...
- 【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目 目录索引
索引 [无私分享:从入门到精通ASP.NET MVC]从0开始,一起搭框架.做项目(1)搭建MVC环境 注册区域 [无私分享:从入门到精通ASP.NET MVC]从0开始,一起搭框架.做项目(2)创建 ...
- 精通ASP.Net MVC 3 框架(第三版)学习笔记
精通ASP.Net MVC 3 框架(第三版)学习笔记 代码才是王道. http://pan.baidu.com/s/1pJyL1cn
- 第 4 章—— C# 语言特性(《精通 ASP.NET MVC 5》)
这里只提供各个特性的简单概括. C# 的完整指南可参阅<Introducing Visual C#>.深度了解 LINQ 可参考<Pro LINQ in C#> 4.1 准备示 ...
- 精通 ASP.NET MVC 4 学习笔记(一)
这里记录着从 P132 到 P192 的内容.水分很足,大部分是书上的代码,我只加了一些基于我自己的理解的能帮助初学者看懂的注释,并且把书中的部分内容做了一些的拓展. 建立数据层 设置 DI 容器 / ...
- 【开源分享:入门到精通ASP.NET MVC+EF6+Bootstrap】从这里开始,一起搭框架(1)开篇介绍
框架简介 这几年一直在做ASP.NET开发,几年前做项目都是老老实实一行行的写代码,后来发现那些高手基本都会有自己积累起来的代码库,现在称之为开发框架,基础代码不用再去堆,主要精力可以集中在业务逻辑实 ...
- 使用整体模型模板辅助器 Using Whole-Model Templated Helpers 模板辅助器方法 精通ASP.NET MVC 5
怎么会
- Creating Form Elements --Using BeginForm and EndForm 使用内建的Form辅助器方法 精通ASP.NET MVC 5
Using the BeginForm and EndForm Helper Methods in the CreatePerson.cshtml File
随机推荐
- ACM题目————STL + 全排列
今天碰到一个函数,感觉挺好用的,全排列函数 next_permutation! 求全排列的函数,基本上与自己写的DFS时间复杂度差不多,毕竟是标准库.(2018-1-4 添加) 话不多说,直接上题. ...
- rabbitmq架构简介(包括集群)
总的来说,rabbitmq使用erlang语言编写,其架构类似于servlet容器运行servlet应用,底层是erlang VM.然后是erlang节点,上面是应用.如下所示: 每个MQ中运行的应用 ...
- keepalived+nginx实现HA高可用的web负载均衡
Keepalived 是一种高性能的服务器高可用或热备解决方案, Keepalived 可以用来防止服务器单点故障的发生,通过配合 Nginx 可以实现 web 前端服务的高可用.Keepalived ...
- 20145127《java程序设计》第三周学习总结
教材学习内容总结 第四章 认识对象 4.1 类与对象 0.Java中有基本类型和类类型两个类型系统.本章主要讲的是类类型.java编写几乎都要使用对象,要产生对象必须先定义类.类是对象的设计图,对象是 ...
- 20145225《网络对抗》Exp8 Web基础
参考博客:5215~ 这次试验,没搞懂,只做了一部分,求老师酌情给分啊 啊啊 基础问题回答 什么是表单? 表单是一个包含表单元素的区域,表单元素是允许用户在表单中(比如:文本域.下拉列表.单选框.复选 ...
- poj 2777 Count Color - 线段树 - 位运算优化
Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 42472 Accepted: 12850 Description Cho ...
- HttpClient4.5简单使用
一.HttpClient简介 HttpClient是一个客户端的HTTP通信实现库,它不是一个浏览器.关于HTTP协议,可以搜索相关的资料.它设计的目的是发送与接收HTTP报文.它不会执行嵌入在页面中 ...
- HttpClient 的使用
HttpClient使用: maven: <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient ...
- 递增三元组|2018年蓝桥杯B组题解析第六题-fishers
标题:递增三元组 给定三个整数数组 A = [A1, A2, ... AN], B = [B1, B2, ... BN], C = [C1, C2, ... CN], 请你统计有多少个三元组(i, j ...
- 【基础配置】Dubbo的配置及使用
1. Dubbo是什么? Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案.简单的说,dubbo就是个服务框架,如果没有分布式的需求,其实是不需 ...