1

我发现自己在围绕基于字符串的“服务定位器”概念的模糊问题上苦苦挣扎。

对于初学者来说,IoC 很棒,而对接口进行编程是要走的路。但是,除了无需编译的可重构性之外,我看不出这里使用的黄页模式的最大好处在哪里。

应用程序代码将使用(Spring)容器从中检索对象。现在这很好:因为代码只需要知道所需的接口(要转换为)、Spring 容器接口和所需对象的名称,因此消除了很多耦合。

public void foo(){
   ((MyInterface) locator.get("the/object/I/need")).callMe();
}

当然,定位器可以填充大量各种Object衍生对象的对象。

但我有点困惑的是,按名称检索对象的“灵活性”实际上以类型不安全、查找不安全的方式隐藏了依赖关系:我的编译器用来检查请求的对象成员是否存在,它是类型,现在所有这些都被推迟到运行时阶段。

我能想到的最简单、功能上还不错的模式是一个巨大的、应用范围内struct的对象:

public class YellowPages  {
    public MyInterface the_object_i_need;
    public YourInterface the_object_you_need;
    ....
}

// context population (no xml... is that bad?)
YellowPages locator = new YellowPages();
locator.the_object_i_need=new MyImpl("xyx",true),
locator.the_object_you_need=new YourImpl(1,2,3)


public void foo(){
   locator.the_object_i_need.callMe(); // type-safe, lookup-safe
}

是否有办法/模式/框架要求编译器解析请求的对象,并检查它的类型是否正确?是否有 DI 框架也可以做到这一点?

非常感谢

4

2 回答 2

2

您所描述的是一种反模式,简单明了。依赖注入(如果可能,通过构造函数完成)是进行控制反转的首选方式。关于 IOC 的较早文章将服务定位作为实现该模式的可行方式,但您很难在最近的著作中找到任何人提倡这一点。

你用这样的说法一针见血:

但我有点困惑的是,按名称检索对象的“灵活性”实际上以类型不安全、查找不安全的方式隐藏了依赖关系:

大多数现代 DI 框架可以绕过类型不安全部分,但它们确实通过使其隐式而不是显式来隐藏依赖关系。

关于这个主题的好文章:

服务定位器是一种反模式

于 2011-09-08T21:53:37.707 回答
2

Spring 是我用过的唯一 DI 框架,所以我不能代表其他人,但即使 Spring 让您能够在代码中通过对象名称请求对象,您也不必获取Spring bean顾名思义——事实上,如果你这样做了,你并没有真正利用 IOC 中的“I”(反转)。

Spring/DI 背后的整个原则是,您的对象不应该请求特定的对象——它应该只需要 IOC 容器交给它的任何对象。区别是微妙的,但它就在那里。前一种方法类似于您粘贴的代码:

public void foo(){
   ((MyInterface) locator.get("the/object/I/need")).callMe();
}

相比之下,后一种方法不依赖于任何服务定位器,也不依赖于它想要的对象的“名称”:

private ObjectINeed objectINeed;

public void setObjectINeed(ObjectINeed objectINeed) {
    this.objectINeed = objectINeed;
}

public void foo(){
   objectINeed.callMe();
}

It's the IOC container that calls the setObjectINeed() method. DI is definitely tackles the same problem as the service locator pattern, but it goes that extra step towards getting rid of the dependency on your service locator class.

于 2011-09-08T21:54:54.240 回答