Java 简单的IOC容器类有什么问题?

Java 简单的IOC容器类有什么问题?,java,architecture,inversion-of-control,ioc-container,testability,Java,Architecture,Inversion Of Control,Ioc Container,Testability,上一天,我在我的一个游乐场项目中实现了一个简单的类作为IOC容器(不太像那样),一些专业人士告诉我,在测试代码时会遇到一些问题(太难分享到底是什么问题!!) 虽然我自己总是使用IOC框架,但我想知道为什么这种方法不好 我甚至用这种方法编写了许多测试(使用模拟框架),从来没有遇到过问题 我想听听你对这个设计问题的看法: public class IocContainer{ private static IocContainer instance; private IocContaine

上一天,我在我的一个游乐场项目中实现了一个简单的类作为IOC容器(不太像那样),一些专业人士告诉我,在测试代码时会遇到一些问题(太难分享到底是什么问题!!)

虽然我自己总是使用IOC框架,但我想知道为什么这种方法不好

我甚至用这种方法编写了许多测试(使用模拟框架),从来没有遇到过问题

我想听听你对这个设计问题的看法:

public class IocContainer{

  private static IocContainer instance;

  private IocContainer(){
  }

  public static IocContainer getInstance()
  {
    if(instance == null){
      instance = new IocContainer();
    }
    return instance;
  }

  public ChatPresenter getChatPresenter(ChatView chatView)
  {
    return new ChatPresenterImpl(chatView, getChatRepo() , getMessagingService());
  }

  private ChatRepo getChatRepo()
  {
    return new ChatRepoImpl(getDbHelper(), getRemoteService());
  }

  private MessagingService getMessagingService()
  {
    return new MessagingServiceImpl()
  }

  private DbHelper getDbHelper()
  {
    return new DbHelperImpl();
  }

  private RemoteService getRemoteService()
  {
    return new RemoteServiceImpl();
  }
}
正如您所见,我只让getChatPresenter可访问,我在视图中使用了下面的方法,效果很好

ChatPresenter presenter = IocContainer.getInstance().getChatPresenter(this)
代码在没有任何紧耦合(使用接口)的情况下处理控制反转

我想知道这种方法有什么不对的地方吗?(我想从技术角度得到答案,因为我已经知道使用Ioc容器库更容易,并且有更多的功能,比如作用域等等……)

实际上,我想知道这种方法在未来会造成什么问题和限制


残忍地杀了我:D

总结一下评论线索:

您的方法看起来像Martin Fowler在这里描述的服务定位器:

Martin描述的内容与您的代码之间有一个主要区别:您的代码直接创建服务的实例,因此更像是一个工厂而不是一个注册表

控制反转的基本思想/目标是通过减少依赖性来减少耦合,如果容器依赖于服务实现(它需要直接调用构造函数),则不会发生这种情况。因此,您问题中的实现在某种程度上反对这一基本想法

依赖于实现的缺点之一是,如果不重新编译容器,就无法替换服务。如果您很可能永远不会有不同的实现,那么这可能不是问题,但是如果您可能需要它,服务注册中心将更有用

注册中心通常提供注册服务实现并根据请求交付服务的方法。交付的方法取决于您的需要,但可能与第一个实现一样简单,也可能更复杂,例如通过匹配一些参数(有关的一些想法,请查看CDI注入点参数和备选方案)


注册表通常伴随着一些配置注册表的方法,例如通过配置文件或类路径扫描(自动查找存在的插件)。但是,只编写一些配置注册表的代码可能就足够了。这完全取决于您需要消除什么耦合(以解决您面临的问题)以及可以接受哪种耦合。

私有静态实例-甚至无法编译…请查看此处:。您的代码基本上看起来像服务定位器方法,但您的容器不是其他人填充的注册表,而是创建实例本身的工厂。好吧,限制是,
IocContainer
始终取决于接口的具体实现,因此它与这些接口相耦合。使用服务注册中心,您可以将其倒置,例如,让您的服务实现自行注册,或者由某种加载机制进行注册。这将允许您添加或替换服务,而无需重新编译
IocContainer
-本质上,IoC是为了减少耦合,这就是为什么你要费心给你的应用程序增加复杂性的原因。它可能是多个映射,甚至是像
Set presenters
等集(你可以根据需要选择一个,可能只是第一个)。此外,您还需要确保在需要时(或之前)解决依赖关系,即当视图请求演示者时,它应该已经存在-演示者最晚需要在该时间解决。通常,在配置时,您可以假设依赖项将存在,允许它们丢失,或者检查它们是否可用,如果不可用则中止(您通常会在启动时这样做)。将这样做:)除此之外,对于什么是好的代码设计有不同的观点。Java世界倾向于提供从未发生过的情况(比如提供未使用的插件机制),因此如果您认为您永远不需要这种情况,那么更简单的设计可能仍然可以。这也是一篇关于使用IOC容器时常见错误的文章:@AmirZiarati感谢链接。当谈到依赖注入时,我建议您看看CDI(JavaEE的一部分)、Guice等框架——当谈到解耦时,我使用CDI取得了一些成功(例如,当JVM加载实现时,实现将自己注册到注册表)。