我相信这些问题已经以某种方式或其他方式提出,但我还没有得到它。
我们做了一个GWT项目,我的项目负责人不允许使用GIN / Guice作为DI框架(新的程序员不会理解它,他认为)所以我尝试手动进行DI。
现在我遇到了深度对象图的问题。 UI中的对象层次结构如下所示:
AppPresenter-> DashboardPresenter-> GadgetPresenter-> GadgetConfigPresenter
对象层次结构树中的GadgetConfigPresenter方式有一些依赖项,如CustomerRepository,ProjectRepository,MandatorRepository等。
因此,创建GadgetConfigPresenter的GadgetPresenter也具有这些依赖关系,依此类推,直到创建AppPresenter的应用程序的入口点。
答案 0 :(得分:8)
你写的那个
GadgetPresenter创建GadgetConfigPresenter [。]
而不是直接创建GadgetConfigPresenter
个实例,而GadgetPresenter
应该take a dependency on an Abstract Factory可以为其创建GadgetConfigPresenter
个实例。这将GadgetConfigPresenter
的内部依赖关系推送到工厂。
一直使用构造函数注入,穷人的DI 布线看起来应该是这样的(对于C#语法道歉):
var customerRepository = new CustomerRepository(/*...*/);
var projectRepository = new ProjectRepository(/*...*/);
var mandatorRepository = new MandatorRepository(/*...*/);
var gadgetConfigPresenterFactory =
new GadgetConfigPresenterFactory(
customerRepository,
projectRepository,
mandatorRepository);
var gadgetPresenter = new GadgetPresenter(gadgetConfigPresenterFactory);
var dashboardPresenter = new DashboardPresenter(gadgetPresenter);
var appPresenter = new AppPresenter(dashboardPresenter);
请注意我们经常打破依赖关系链,确保每个消费者的依赖关系数量永远不会变得太大。
原则上,这意味着您必须在启动时创建所有依赖项,除非您实现lazy loading strategy。
管理生命周期这样的事情就是DI容器非常有用的东西,但完全有可能只用following DI patterns and principles编写整个应用程序。
总而言之,如果可能的话,我仍然会推荐一个DI容器。
答案 1 :(得分:0)
您可以使用Context接口进行DI。这并不难,也很直接。
Context接口是一个公开来自guice模块配置的所有绑定的类。
这是一个例子,我假设AppPresenter + DashboardPresenter在一个包中并且需要一个“上下文”,而GadgetPresenter和GadgetConfigPresenter在另一个包中并且需要另一个“上下文”。上下文的数量以及如何处理它们完全取决于用户。
/**
* The dependencies that need to be injected for package1
*/
public interface SomePackageContext {
GadgetPresenter getGadgetPresenter();
GadgetConfigPresenter getGadgetConfigPresenter();
}
/**
* The dependencies that need to be injected for package2
*/
public interface OtherPackageContext {
// These methods can take arguments..
AppPresenter getAppPresenter(Args..);
DashboardPresenter getDashboardPresenter(Args..);
}
/**
* All of the DI needed in our project.
*
* <p>We don't need the two interfaces above, we can put
* everything in this interface if we have a small
* project where layering is not a big issue.
*/
public interface PresenterContext
extends SomePackageContext, OtherPackageContext {
}
public class MockPresenterContext implements PresenterContext {
...
}
public class RealPresenterContext implements PresenterContext {
// This is similar to bind(...) in guice
public AppPresenter getAppPresenter(Args..) {
return new AppPresenter(this, otherargs...);
}
public DashboardPresenter getDashboardPresenter(Args..) {
return new DashboardPresenter(this, otherargs...);
}
public GadgetPresenter getGadgetPresenter() {
return new GadgetPresenter(this);
}
public GadgetConfigPresenter getGadgetConfigPresenter() {
return new GadgetConfigPresenter();
}
}
public class DashboardPresenter {
// @Inject
private final GadgetPresenter gadgetPresenter;
/*
* We inject everything using the SomePackageContext.
*/
public DashboardPresenter(SomePackageContext ctxt) {
this.gadgetPresenter = ctxt.getGadgetPresenter();
}
}