Spring 通过名称查找质疑依赖项注入

Spring 通过名称查找质疑依赖项注入,spring,design-patterns,dependency-injection,type-safety,yellow-pages,Spring,Design Patterns,Dependency Injection,Type Safety,Yellow Pages,我发现自己正在与基于字符串的“服务定位器”概念的模糊性作斗争 对于初学者来说,IoC很棒,编程到接口就是一条出路。但是,除了编译更少的可重构性之外,我看不出这里使用的黄页模式的最大好处在哪里 应用程序代码将使用Spring容器从中检索对象。这很好:因为代码只需要知道要转换到的所需接口、Spring容器接口和所需对象的名称,所以很多耦合都被删除了 public void foo(){ ((MyInterface) locator.get("the/object/I/need")).callM

我发现自己正在与基于字符串的“服务定位器”概念的模糊性作斗争

对于初学者来说,IoC很棒,编程到接口就是一条出路。但是,除了编译更少的可重构性之外,我看不出这里使用的黄页模式的最大好处在哪里

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

public void foo(){
   ((MyInterface) locator.get("the/object/I/need")).callMe();
}
当然,定位器可以被各种各样的物体衍生物所填充

但我有点困惑于这样一个事实:按名称检索对象的“灵活性”实际上以一种类型不安全、查找不安全的方式隐藏了依赖关系:我的编译器过去用于检查请求对象成员的存在及其类型,现在所有这一切都推迟到运行时阶段

我能想到的最简单的、功能上完全正确的模式是一个巨大的、应用程序范围的类似结构的对象:

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框架也这样做


非常感谢

您所描述的是一种简单明了的反模式。如果可能的话,通过构造函数进行依赖注入是实现控制反转的首选方法。关于国际奥委会的老文章谈到服务定位是实现这一模式的可行方式,但在最近的文章中,你很难找到支持这一模式的人

你的话一针见血:

但我对检索的“灵活性”感到有点困惑 按名称命名的对象实际上隐藏了不安全类型中的依赖项, 查找不安全的方式:

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

关于这个话题的好文章:


你所描述的是一种反模式,简单明了。如果可能的话,通过构造函数进行依赖注入是实现控制反转的首选方法。关于国际奥委会的老文章谈到服务定位是实现这一模式的可行方式,但在最近的文章中,你很难找到支持这一模式的人

你的话一针见血:

但我对检索的“灵活性”感到有点困惑 按名称命名的对象实际上隐藏了不安全类型中的依赖项, 查找不安全的方式:

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

关于这个话题的好文章:


Spring是我使用过的唯一DI框架,因此我不能代表其他人,但即使Spring允许您在代码中按名称请求对象,您也不必按名称获取SpringBean—事实上,如果您这样做,您并没有真正利用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();
}

是IOC容器调用SetObjectNeed方法。DI确实解决了与服务定位器模式相同的问题,但它朝着摆脱对服务定位器类的依赖迈出了额外的一步。

Spring是我使用过的唯一DI框架,因此我不能代表其他人,但即使Spring允许您在代码中按对象名称请求对象,你不必按名字来获得你的SpringBean——事实上,如果你这么做了,你就没有真正利用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();
}
是IOC容器调用SetObjectNeed方法。DI确实解决了与服务定位器模式相同的问题,但它朝着摆脱对服务定位器类的依赖迈出了额外的一步