这两种模式似乎都是控制反转原理的实现。也就是说,一个对象不应该知道如何构造它的依赖项。
依赖注入(DI)似乎使用构造函数或setter来“注入”它的依赖项。
使用构造函数注入的例子:
//Foo Needs an IBar
public class Foo
{
private IBar bar;
public Foo(IBar bar)
{
this.bar = bar;
}
//...
}
Service Locator似乎使用了一个“容器”,它连接了它的依赖项并给了foo它的bar。
使用Service Locator的例子:
//Foo Needs an IBar
public class Foo
{
private IBar bar;
public Foo()
{
this.bar = Container.Get<IBar>();
}
//...
}
因为我们的依赖关系只是对象本身,这些依赖关系有依赖关系,依赖关系有更多依赖关系,等等。因此,控制反转容器(或DI容器)诞生了。例如:Castle Windsor, Ninject, Structure Map, Spring等)
但是IOC/DI容器看起来完全像服务定位器。称它为DI容器是一个坏名字吗?IOC/DI容器只是另一种类型的服务定位器吗?当我们有很多依赖时,我们使用依赖注入容器,这是一个细微的差别吗?
Martin Fowler说:
使用服务定位器,应用程序类将显式地通过
消息发送给定位器。对于注入,没有显式的请求,
服务出现在应用程序类中——因此是
控制。
简而言之:服务定位器和依赖注入只是依赖反转原理的实现。
重要的原则是“依赖抽象,而不是具象”。这将使你的软件设计“松散耦合”、“可扩展”、“灵活”。
您可以使用最适合您需要的一种。对于拥有庞大代码库的大型应用程序,您最好使用服务定位器,因为依赖注入将需要对代码库进行更多更改。
你可以查看这篇文章:依赖倒置:服务定位器或依赖注入
还有经典的:Martin Fowler的控制容器反转和依赖注入模式
设计可重用类作者:Ralph E. Johnson和Brian Foote
然而,让我大开眼界的是:ASP。NET MVC:解析还是注入?这就是问题所在,迪诺·埃斯波西托著
郑重声明
//Foo Needs an IBar
public class Foo
{
private IBar bar;
public Foo(IBar bar)
{
this.bar = bar;
}
//...
}
除非你真的需要一个接口(接口被多个类使用),否则你绝对不能使用它。在这种情况下,IBar允许使用实现它的任何服务类。然而,通常,这个接口将由单个类使用。
为什么使用接口不是一个好主意?因为它真的很难调试。
例如,假设实例“bar”失败了,问题:哪个类失败了?我应该修复哪些代码?一个简单的视图,它指向一个界面,我的路到此结束。
相反,如果代码使用硬依赖项,则很容易调试错误。
//Foo Needs an IBar
public class Foo
{
private BarService bar;
public Foo(IBar bar)
{
this.bar = bar;
}
//...
}
如果“酒吧”失败,那么我应该检查和杉木类BarService。