设计模式的控制反转模式
public class EmailService { public void SendMessage() { ...} } public class NotificationSystem { private EmailService svc; public NotificationSystem() { svc=new EmailService(); } public void InterestingEventHappened() { svc.SendMessage(); } }
NotificationSystem类依赖于EmailService类。当一个组件依赖于其他的组件时,我们称之为耦合(coupling)。在上面的代码中在NotificationSystem类的构造函数中,直接创建了EmailService类的实例,这种类知道与它交互的类大量的信息,我们称他为高耦合。
在软件设计中,高耦合通常认为是软件设计者的责任。当一个类精确地知道另外一个类的设计和实现时,就会增加软件修改的负担,因为修改一个类很有可能破坏依赖于它的另外一个类。
为了降低组件之间的耦合性,一般采用两个独立但相关的步骤:
(1)在两个代码之间引入抽象层:在.NET中,我们常用接口(抽象类)来代表两个类之间的抽象层。
public interface IMessageingService { void SendMessage(); } public class EmailService : IMessageingService { public void SendMessage() { ...} } public class NotificationSystem { private IMessageingService svc; public NotificationSystem() { svc=new EmailService(); // } public void InterestingEventHappened() { svc.SendMessage(); } }
这样一来,NotificationSystem类中的私有副本就变成了接口的一个实例,而不是具体的类型,并且对其构造函数隐藏了实际类型
(2)将选择抽象实现的责任移到消费类的外部:需要将EmailService类的创建移到NotificationSystem类的外面。
将依赖的创建移到使用这些依赖类的外部,这称为控制反转模式,之所以这样命名,是因为反转的是依赖的创建,正因为如此,才消除了消费类对依赖创建的控制。
控制反转(Ioc)模式是抽象的:它只是表述应该从消费类中移除依赖创建,而没有表述如何实现
服务定位器是控制反转模式的一种实现方式,他通过一个称为服务定位器的外部组件来为需要依赖的组件提供依赖。服务定位器有时是一个具体的接口,为特定服务提供强类型、泛型、任意类型的请求服务。
(1). 强类型的服务定位器
public interface IserviceLocator { IMessageingService GetMessageingService(); } public class NotificationSystem { private IMessageingService svc; public NotificationSystem(IserviceLocator locator) { svc = locator.GetMessageingService(); } }
(2)弱类型服务定位器
public interface IserviceLocator { object GetService(Type serviceType); T GetService<T>(); } public class NotificationSystem { private IMessageingService svc; public NotificationSystem(IserviceLocator locator) { svc = (IMessageingService)locator.GetService(typeof(IMessageingService)); svc = locator.GetService<IMessageingService>(); } public void InterestingEventHappened() { svc.SendMessage(); } }
依赖注入(Dependency Injection)DI是控制反转模式的另外一种形式;
(1)构造函数注入
public class NotificationSystem { private IMessageingService svc; public NotificationSystem(IMessageingService service) { svc = service; } public void InterestingEventHappened() { svc.SendMessage(); } }
(2)属性注入
public class NotificationSystem { private IMessageingService MessagingService { get; set; } public void InterestingEventHappened() { if (MessagingService != null) MessagingService.SendMessage(); } }
(3)依赖注入容器
依赖注入容器是依赖解析变得简单的一种方式。依赖注入容器是一个可以作为组件工厂使用的软件库,它可以自动检测和满足里面元素的依赖要求。