一个简单的 IOC 容器有什么问题 class?
whats wrong with a simple IOC container class?
最后一天我在我的一个 playground 项目中实现了一个简单的 class 作为 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 在此处描述的服务定位器:http://martinfowler.com/articles/injection.html#InversionOfControl
Martin 描述的内容与您的代码之间存在重大差异:您的代码直接创建服务的实例,因此与其说是注册中心,不如说是工厂。
控制反转的基本 idea/goal 是通过减少依赖性来减少耦合,如果您的容器依赖于服务实现(它需要直接调用构造函数),则不会发生这种情况。所以你问题中的实现有点反对这个基本想法。
依赖于实现的缺点之一是如果不重新编译容器就无法替换服务。如果您很可能永远不会有不同的实现,那可能不是问题,但如果您可能需要它,服务 registry 会更有用。
注册表通常提供注册服务实现并根据请求提供服务的方法。交付哪个取决于您的需求,但它可能与找到的第一个实现一样简单,也可能更复杂,例如通过匹配一些参数(如需一些想法,请查看 CDI 注入点参数和备选方案)。
注册中心一般都会附带一些配置注册中心的手段,例如通过配置文件或类路径扫描(自动查找存在的插件)。但是,仅编写一些配置注册表的代码也可能就足够了。这完全取决于你需要摆脱什么样的耦合(以解决你面临的问题)以及哪种耦合是可以接受的。
最后一天我在我的一个 playground 项目中实现了一个简单的 class 作为 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 在此处描述的服务定位器:http://martinfowler.com/articles/injection.html#InversionOfControl
Martin 描述的内容与您的代码之间存在重大差异:您的代码直接创建服务的实例,因此与其说是注册中心,不如说是工厂。
控制反转的基本 idea/goal 是通过减少依赖性来减少耦合,如果您的容器依赖于服务实现(它需要直接调用构造函数),则不会发生这种情况。所以你问题中的实现有点反对这个基本想法。
依赖于实现的缺点之一是如果不重新编译容器就无法替换服务。如果您很可能永远不会有不同的实现,那可能不是问题,但如果您可能需要它,服务 registry 会更有用。
注册表通常提供注册服务实现并根据请求提供服务的方法。交付哪个取决于您的需求,但它可能与找到的第一个实现一样简单,也可能更复杂,例如通过匹配一些参数(如需一些想法,请查看 CDI 注入点参数和备选方案)。
注册中心一般都会附带一些配置注册中心的手段,例如通过配置文件或类路径扫描(自动查找存在的插件)。但是,仅编写一些配置注册表的代码也可能就足够了。这完全取决于你需要摆脱什么样的耦合(以解决你面临的问题)以及哪种耦合是可以接受的。