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

あなたはそれを書きます

GadgetConfigPresenter[.] を作成する GadgetPresenter

GadgetConfigPresenterインスタンスを直接作成する代わりに、インスタンスを作成できる抽象ファクトリに依存するGadgetPresenter必要があります。これにより、内部の依存関係がファクトリにプッシュされます。GadgetConfigPresenterGadgetConfigPresenter

コンストラクター インジェクションを最後まで使用すると、Poor Man's 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 コンテナーをお勧めします。

于 2010-03-11T14:20:07.360 に答える
0

Context インターフェイスを使用して DI を実行できます。難しいことはなく、かなり簡単です。

Context インターフェースは、guice モジュール構成からすべてのバインディングを公開するクラスです。

これは、AppPresenter+DashboardPresenter が 1 つのパッケージにあり、1 つの「コンテキスト」が必要であり、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 に答える