8

我相信已经以某种或其他方式提出了这个问题,但我还没有得到它。

我们做了一个 GWT 项目,我的项目负责人不允许使用 GIN/Guice 作为 DI 框架(他认为新程序员不会理解它)所以我尝试手动进行 DI。

现在我遇到了深度对象图的问题。UI 中的对象层次结构如下所示:

AppPresenter->DashboardPresenter->GadgetPresenter->GadgetConfigPresenter

GadgetConfigPresenter 沿着对象层次结构树向下有一些依赖项,如 CustomerRepository、ProjectRepository、MandatorRepository 等。

因此,创建 GadgetConfigPresenter 的 GadgetPresenter 也具有这些依赖项等,直到创建 AppPresenter 的应用程序的入口点。

  • 这是手动DI应该工作的方式吗?
  • 这是否意味着我在启动时创建了所有依赖项,即使我不需要它们?
  • 像 GIN/Guice 这样的 DI 框架会在这里帮助我吗?
4

2 回答 2

11

你这样写

GadgetPresenter 创建 GadgetConfigPresenter[.]

与其直接创建GadgetConfigPresenter实例,GadgetPresenter不如依赖可以为其创建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);

注意我们如何经常打破依赖链,确保每个消费者的依赖数量永远不会变得太大。

原则上,这意味着您必须在启动时创建所有依赖项,除非您实施延迟加载策略

诸如管理生命周期之类的事情正是 DI 容器可以提供极大帮助的事情,但是完全可以通过遵循 DI 模式和原则来编写整个应用程序。

总而言之,如果可能的话,我仍然会推荐一个 DI Container。

于 2010-03-11T14:20:07.360 回答
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();
  }
}
于 2010-03-12T13:30:24.717 回答