Dependency Inversion The Dependency Inversion Principle有清楚的解释。
简单的说,在模块设计时,高层的抽象模块通常是与业务相关的模块,它应该具有重用性,而不依赖于低层的具体模块,例如如果低层模块原先是软盘存取模式,而高层模块是个存盘备份的需求,如果高层模块直接调用低层模块的函数,则就对低层模块产生了依赖关系。
举个例子,例如下面这个c程序:
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
在这个程序中,BusinessObject 的存盘依赖于实际的 FloppyWriter,如果今天想要将存盘改为存至 Usb 硬盘,则必须修改或继承 BusinessObject 进行扩展,而无法直接使用BusinessObject。
如果透过接口的声明,可以改进此一情况,例如:
public interface IDeviceWriter {
public void SaveToDevice();
}
public class BusinessObject {
private IDeviceWriter writer;
public DeviceWriter
{
Set
{
this.writer = value;
}
}
public void Save() {
![]()
.
writer.SaveToDevice();
}
}
这样一来,BusinessObject 就是可重用的,如果今天有存储至 Floppy 或 Usb 硬盘的需求,只要实现 IDeviceWriter 即可,而不用修改 BusinessObject:
public class FloppyWriter :IDeviceWriter {
public void SaveToDevice() {
![]()
.
// 实现储存至Floppy的程序代码
}
}
public class UsbDiskWriter : IDeviceWriter {
public void SaveToDevice() {
![]()
.
// 实现储存至UsbDisk的程序代码
}
}
从这个角度来看,Dependency Inversion 的意思就是程序不依赖于具体实现,而是程序与实现都要依赖于抽象。 IoC 的 Control 是控制的意思,其实其背后的意义也是一种依赖关系的转移,如果A依赖于B,其意义即是B拥有控制权,您想要转移这种关系,所以依赖关系的反转即是控制关系的反转,藉由控制关系的转移,可以获得组件的可重用性,在上面的 .NET 程序中,整个控制权从实际的 FloppyWriter 转移到抽象的 IDeviceWriter 接口上,使得BusinessObject、FloppyWriter、UsbDiskWriter 这几个实现依赖于抽象的 IDeviceWriter 接口。
程序的业务逻辑部份应该是可以重用的,不应受到所使用框架或容器的影响,因为可能转移整个业务逻辑至其它的框架或容器,如果业务逻辑过于依赖容器,则转移至其它的框架或容器时,就会发生困难。
IoC 在容器的角度,可以用这么一句好莱坞名言来代表:"Don't call me, I'll call you." 以程序的术语来说的话,就是“不要向容器要求您所需要的(对象)资源,容器会自动将这些对象给您!”。IoC 要求的是容器不侵入应用程序本身,应用程序本身提供好接口,容器可以透过这些接口将所需的资源注入到程序中,应用程序不向容器主动要求资源,故而不会依赖于容器的组件,应用程序本身不会意识到正被容器使用,可以随时从容器中脱离转移而不用作任何的修改,而这个特性正是一些业务逻辑中间件最需要的。