加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

依赖注入

发布时间:2020-12-14 05:34:08 所属栏目:百科 来源:网络整理
导读:? ? ?在MVC架构中,整个系统被分离为许多单独的模块(仅仅对于根据用户请求得到合适的数据这一个功能来讲,至少存在M与C的分离),而MVC设计者的初衷之一就是实现各个模块间的松耦合,即相互间的关联性更
? ? ?在MVC架构中,整个系统被分离为许多单独的模块(仅仅对于根据用户请求得到合适的数据这一个功能来讲,至少存在M与C的分离),而MVC设计者的初衷之一就是实现各个模块间的松耦合,即相互间的关联性更小。

? ? ?先举例如下:
? ? ?在一个系统中,我们需要建立一个Email系统,实现Email的发送;
? ? ?最简单的实现是直接创建一个EmailSender的模块,但是考虑到系统的扩展性,今后可能会改变Emial发送的方式,或者会提供更多的Emal发送的方式时,更好的方法是先创建一个IEmailSender的接口,提供一系列的方法声明:我们需要一个(或多个)这样的模块,这个(些)模块必须至少能完成接口IEmailSender中承诺的功能,然后让EmailSender实现该接口。
? ? ?假如需要完成一个通过发送邮件来找回密码这样的功能模块PassWordHelp时,可以不用直接调用EmailSender,而通过调用IEmailSender里的方法来完成这一功能。如此可以实现对某个功能的调用,和该功能具体的实现进行分离,方便各个模块的扩展。如下:

? ? ? ? ? ? ?

代码实现如下:

public interface IEmailSender
{
? ? ?public void SendEmial;
}

?public class MyEmailSender:IEmailSender
{
? ? ?public void SendEmail()
?????{
? ? ??????// 实现邮件发送
?????}
}

public class PasswordResetHelper?
{
public void ResetPassword()?
{
?????IEmailSender? mySender = new MyEmailSender();
?????// 调用EmailSender 里的方法来实现邮件发送
?????mySender.SendEmail();
}
}

?????对于模块A而言,当他需要和模块B协同完成某项功能时,在模块A中,需要模块B提供的仅仅是接口,如果需要在模块A中实现模块B的实例来完成相关的任务,就产生了模块B的依赖,依赖的缺陷之一就是如果模块B中提供了某个功能的多种实现,或者以后发生了更改,在A中就必须考虑到这些细节。依赖的缺陷之二就是在测试时,必须在模块A中实现模块B的实例所需的所有信息,这对于单体测试以及整体测试而言,确实不如直接调用模块B提供的接口方便。
?????正如上面的例子中,在 PasswordResetHelper 模块中,IEmailSender? mySender = new MyEmailSender();这句产生了依赖关系,假如今后需要发送邮件的方式不是MyEmailSender提供的方式,就必须去更改 PasswordResetHelper?模块中的代码了。很明显, PasswordResetHelper 对EmailSender这种依赖不利于系统扩展。
? ? ?对于上述问题的解决方案,就是依依赖注入(DI),或者叫做控制反转(IoC),还是先举例如下:
? ? ?修改 PasswordResetHelper 中的代码如下:
? ? ? ? ? ? ?public class PasswordResetHelper?
? ? ? ? ? ? ?{
?????????????????????????public void ResetPassword(IEmailSender mySender)?
? ? ? ? ? ? ? ? ? ? ? ? ?{
??????????????????????????????mySender.SendEmail();
?????????????????????????}
? ? ? ? ? ? ?}

? ? ?如此,至于 PasswordResetHelper 中所需要的 IEmailSender?接口中的功能中究竟是哪个模块实现的,这与 PasswordResetHelper?无关,只需要把 IEmailSender?的某个实例传入就行了。更通行的做法是专门建一个把接口机 IEmailSender?和实现 IEmailSender?的实例MyEmailSender关联起来的容器,当需要 IEmailSender ?的实例时,会自动产生MyEmailSender的实例传入 ResetPassword方法中。这样实现了把模块A对模块B的依赖抽取到模块A以外去单独管理,然后把依赖的实例传入模块A中,或许这就是"依赖注入"名称的来源吧。
? ? ?当然,上例中,是通过在构造方法中把依赖以构造方法的参数的方式来实现的,还可以通过把依赖以Public属性的方式注入,如下:
public class? PasswordResetHelper?
{
? ? ?private? IEmailSender?? mySender;
? ? ?public? PasswordResetHelper ()
?????{
? ? ? ? ?// 通过调用实现
?????IEmailSender?接口与具体实例的映射的外部方法来得到 IEmailSender?
? ? ? ? ? mySender=new SomeMethod();
?????}
}

? ? ?至于如何实现 IEmailSender?接口与该接口的具体实例MyEmailSender关联,在需要 ?的接口时产生对应的实例,最简单的就是自己写代码,通过new来实现。但现在有许多比较好的DI容器,可以很方便的管理接口(包括抽象类)的实例,完成好相关配置后,可以实现自动生成对应的实例传递。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读