第13章 依赖注入

前端之家收集整理的这篇文章主要介绍了第13章 依赖注入前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

一、 软件设计模式

为更好地理解依赖注入的概念,以及如何将其应用于MVC程序中,首先了解一下软件设计模式是很有必要的。
1 、设计模式——控制反转模式
代码如下:
  1. public class EmailService
  2. {
  3. public void SendMessage() { }
  4. }
  5. //NotificationSystem类依赖于EmailService类。
  6. //当一个组件依赖于其他组件时,我们称其为耦合。
  7. //通知系统(NotificationSystem)在其构造函数内部直接创建e-mail服务的一个实例
  8. //通知系统精确地知道创建和使用了哪种类型服务(高耦合)
  9. //当修改一个类(EmailService)很可能破坏依赖于它的另一个类(NotificationSystem)
  10. public class NotificationSystem
  11. {
  12. private EmailService svc;
  13. public NotificationSystem()
  14. {
  15. svc = new EmailService();
  16. }
  17. public void InterestingEnentHappened()
  18. {
  19. svc.SendMessage();
  20. }
  21. }
上面代码设计存在一个问题:系统管理员想得到文本信息而不是电子邮件
为降低组件之间的耦合程度,一般采取两个独立单相关的步骤:

(1)在两块代码之间引用抽象层
通常使用接口(或抽象类)来代表两个类之间的抽象层。
我们引用一个接口来代表抽象层,并确保编写的代码调用接口中的方法属性
这样一来,NotificationSystem类中的私有副本就变成接口的一个实例,而不再是具体类型,并且构造函数隐藏了时间类型。
代码如下:
  1. public interface IMessagingService
  2. {
  3. void SendMessage();
  4. }
  5. public class EmailService:IMessagingService
  6. {
  7. public void SendMessage() { }
  8. }
  9. public class NotificationSystem
  10. {
  11. private IMessagingService svc;
  12. public NotificationSystem()
  13. {
  14. svc = new EmailService();
  15. }
  16. public void InterestingEnentHappened()
  17. {
  18. svc.SendMessage();
  19. }
  20. }


(2)、把选择抽象实现的责任移到消费类的外部。
把 EmailService类的创建移到NotificationSystem类的外面。
控制反转模式是抽象的,它只是表述应该从消费者类中移除依赖创建,而没有表述如何实现。
用控制反转模式实现责任转移的两种常用方法:服务定位器和依赖注入。

2、 设计模式——服务定位器

(1)、强类型服务定位器

  1. //服务定位器(已经预先知道IMessagingService类型对象)
  2. public interface IServiceLocator
  3. {
  4. IMessagingService GetMessagingService();
  5. }
  6. public interface IMessagingService
  7. {
  8. void SendMessage();
  9. }
  10. public class EmailService:IMessagingService
  11. {
  12. public void SendMessage() { }
  13. }
  14. public class NotificationSystem
  15. {
  16. private IMessagingService svc;
  17. public NotificationSystem(IServiceLocator locator)
  18. {
  19. svc = locator.GetMessagingService();
  20. }
  21. public void InterestingEnentHappened()
  22. {
  23. svc.SendMessage();
  24. }
  25. }

(2)、弱类型服务定位器
  1. //弱类型服务定位器,它允许请求任意服务类型
  2. public interface IServiceLocator
  3. {
  4. //Object版本的GetService
  5. Object GetService(Type serviceType);
  6. ////从.NET 2.0引入泛型以来,出现泛型版本GetService
  7. //TService GetService<TService>();
  8. }
  9. //IServiceLocator扩展方法
  10. public static class ServiceLocatorExtensions
  11. {
  12. public static TService GetService<TService>(this IServiceLocator locator)
  13. {
  14. return (TService)locator.GetService(typeof(TService));
  15. }
  16. }
  17. public interface IMessagingService
  18. {
  19. void SendMessage();
  20. }
  21. public class EmailService:IMessagingService
  22. {
  23. public void SendMessage() { }
  24. }
  25. public class NotificationSystem
  26. {
  27. private IMessagingService svc;
  28. public NotificationSystem(IServiceLocator locator)
  29. {
  30. svc = (IMessagingService)locator.GetService(typeof(IMessagingService));//Object版本
  31. svc = locator.GetService<IMessagingService>();//泛型版本
  32. }
  33. public void InterestingEnentHappened()
  34. {
  35. svc.SendMessage();
  36. }
  37. }

服务定位器的用法比较简单:我们先从某个地方得到服务定位器,然后利用定位器查询依赖。
组件需求的不透明性,促使我们选择下一个反转控制模式:依赖注入

3 、设计模式—— 依赖注入

  1. //服务接口
  2. public interface IMessagingService
  3. {
  4. void SendMessage();
  5. }
  6. //邮件服务
  7. public class EmailService:IMessagingService
  8. {
  9. public void SendMessage() { }
  10. }

(1)、构造函数注入

  1. //通知系统
  2. public class NotificationSystem
  3. {
  4. private IMessagingService svc;
  5. //构造函数中实现 IMessagingService 接口实例
  6. public NotificationSystem(IMessagingService service)
  7. {
  8. this.svc = service;
  9. }
  10. public void InterestingEnentHappened()
  11. {
  12. svc.SendMessage();
  13. }
  14. }
(2)、属性依赖注入
通过对象上的公共属性来注入依赖。
  1. public class NotificationSystem
  2. {
  3. public IMessagingService MessagingService
  4. {
  5. get;
  6. set;
  7. }
  8. public void InterestingEnentHappened()
  9. {
  10. if (MessagingService == null)
  11. {
  12. throw new InvalidOperationException("先设置MessagingService");
  13. }
  14. MessagingService.SendMessage();
  15. }
  16. }

二、 MVC中的依赖解析

在ASP.NET MVC中的应用
ASP.NET MVC与容器交换的主要方式就是通过为ASP.NET MVC 应用程序创建的一个接口:IDependencyReSolver
public interface IDependencyReSolver
{
object GetService(Type serviceType);
IEnumerable<object> GetService(Type serviceType);
}
该接口 由ASP.NET MVC 框架本身使用。当注册一个依赖注入容器(或服务定位器)时,我们需要实现该接口。
通常可以在Global.asax文件注册一个解析器实例,代码如下:
DependencyResolver.Current = new MyDependencyResolver();


如果能在使用依赖注入时,免去IDependencyReSolver接口的实现就完美了,
我们可以同Nuget查询"IOC"和"dependency"这类短语,会找到一些可以下载的依赖注入容器。
它们能捆绑IDependencyReSolver接口的一个实现。

1、 MVC中的单一注册服务

用户为MVC使用的服务能且仅能注册一个服务实例,此类服务称为单一注册服务,用来从解析器中检索单一注册服务的方法是GetService.


2 、MVC中的复合注册服务

可以注册多个服务实例的服务。我们可以使用GetServices方法从解析器中检索复合注册服务。

ASP.NET MVC支持两个复合服务模型:
竞争服务:按顺序执行服务,并询问服务可否执行其主要功能(如:视图引擎服务)。
协作服务:请求每个服务执行其主要功能,满足请求的所有服务就会协作完成操作(如:过滤器)。

服务:过滤提供器
接口:IFilterProvider
传统注册API:FilterProvider.Providers
复合服务模型:协作
默认服务实现:
FilterAttributeFilterProvider
GlobalFilterCollection
ControllerInstanceFilterProvider

服务:模型绑定器提供器
接口:IModelBinderProvider
传统注册API:ModelBinderProviders.BinderProviders
复合服务模型:竞争

服务:视图引擎
接口:IViewEngine
传统注册API:ViewEngines.Engines
复合服务模型:竞争
默认服务实现:
WebFormViewEngine
RazorViewEngine

服务:模型验证器提供器
类型:ModelValidatorProvider
传统注册API:ModelValidatorProviders.Providers
复合服务模型:协作
默认服务实现:
DataAnnotationsModelValidatorProvider
DataErrorInfoModelValidatorProvider
ClientDataTypeModelValidatorProvider

服务:值提供器工厂
类型:ValueProviderFactory
传统注册API:ValueProviderFactories.Factories
复合服务模型:竞争
默认服务实现:
ChildActionValueProviderFactory
FormValueProviderFactory
JsonValueProviderFactory
RouteDataValueProviderFactory
QueryStringValueProviderFactory
HttpFileCollectionValueProviderFactory

3 、MVC中的任意对象

MVC中有两个特殊的情形。在这两个情形中,MVC框架请求一个依赖解析器来创建任意对象, 这些创建的对象严格来说不是服务,而是控制器和视图页面。 (1)、创建控制器 将控制器名称映射为类型以及将类型实例化为对象。 public interface IControllerActivator { }

三、 Web API中的依赖解析 1、 Web API中的单一注册服务 2 、Web API中的复合注册服务 3 、Web API中的任意对象 4、 对比MVC和Web API中的依赖解析器 四、 小结

猜你在找的设计模式相关文章