依赖注入
- 软件设计模式
为了更好地理解依赖注入的概念,首先了解一下软件设计模式是很有必要的。软件设计模式主要用来规范问题及其解决方案的描述,以简化开发人员对常见问题及其对应解决方案的标识与交流。
- 控制反转IOC
几乎每个人都看过或是自己写过下面代码的经历
1 public class EmailService 2 { 3 public void SendMsg() 4 { 5 Console.WriteLine("Hello world !!!"); 6 } 7 } 8 9 /// <summary> 10 /// 耦合实现 11 /// </summary> 12 public class NotificationSys 13 { 14 private EmailService svc; 15 16 public NotificationSys() 17 { 18 svc = new EmailService(); 19 } 20 21 public void InterestingEventHappened() 22 { 23 svc.SendMsg(); 24 } 25 }
上述代码中,NotificationSys 类依赖EmailService类,当一个组件依赖其他组件称之耦合。在软件设计过程,高耦合通常认为是软件设计的责任。当一个类精确地知道另一个类的设计和实现时,就会增加软件修改的负担,因为修改一个类很有可能破坏依赖它的另一个类。为降低组件之间的耦合程序,一般采取两个独立但相关的步骤:
1.在两块代码之间引入抽象层,所以上述代码可修改为以下
1 public interface IEmailService 2 { 3 void SendMsg(); 4 } 5 public class EmailService : IEmailService 6 { 7 public void SendMsg() 8 { 9 Console.WriteLine("Hello world !!!"); 10 } 11 } 12 /// <summary> 13 /// 抽象接口来实现 14 /// (把抽象实现的责任移到消费者的外部) 15 /// </summary> 16 public class NotificationSys1 17 { 18 private IEmailService svc; 19 public NotificationSys1() 20 { 21 svc = new EmailService1(); 22 } 23 public void InterestingEventHappened() 24 { 25 svc.SendMsg(); 26 } 27 }
2.把选择抽象实现的责任移到消费者类的外部。
控制反转(IOC)模式是抽象的;把依赖的创建移到使用这些的类的外部,这称为控制反转模式,之所以以这样命名,是因为反转的是依赖的创建,正因为如此,才消除消费类对依赖创建的控制。
- 依赖注入DI
依赖注入是另一种控制反转模式形式,它没有像服务器定位器一样的中间对象。相反,组件以一种允许依赖的方式编写,通常由构造函数参数或属性设置器来显式表示。
1. 构造函数注入
DI 的最常见形式是构造函数注入。该技术需要我们为类创建一个显示表示所以依赖的构造函数。
1 /// <summary> 2 /// 构造注入 3 /// </summary> 4 public class NotificationSys 5 { 6 private IEmailService _svc; 7 8 public NotificationSys(IEmailService svc) 9 { 10 _svc =svc ; 11 } 12 public void InterestingEventHappened() 13 { 14 _svc.SendMsg(); 15 } 16 }
优点: 极大简化构造函数的实现;减少了NotificationSys类需要知道的信息量;需求的透明性,任何想创建NotificationSys类实例的代码都能查看构造函数,并精确的知道哪些内容是消费者必须的。
2.属性注入
属性注入是一种不太常见的依赖注入方式。顾名思义,该方式是通过设置对象上公共属性而不是通过使用构造函数参数来注入依赖。
public class NotificationSys { private IEmailService svc{get;set;} public void InterestingEventHappened() { svc.SendMsg(); } }
显而易见,这里我们已经减少了需求的透明性,而且绝对比构造函数注入更容易产生错误。
选择属性注入原因:
如果依赖在某种意义上是真正可选的,即在消费者类不提供依赖时,也有相应的处理,属性注入是个不错的选择
类的实例可能需要在我们还没有控制调用的构造函数的情况下被创建
- 依赖注入容器
依赖注入容器是一个可以作为组件工厂使用的软件库,它可以自动检测和满足里面元素的依赖需求。常见的DI容器有 CastleWindsor,Unity,Autofac, ObjectBuilder,StructureMap,Spring.Net
路漫漫其修远兮, 吾将上下而求索