Locked History Actions

Diff for "AssistedInject"

Differences between revisions 1 and 2
Deletions are marked like this. Additions are marked like this.
Line 3: Line 3:
Factories by Hand == 人手によるファクトリ ==
Line 5: Line 5:
Sometimes a class gets some of its constructor parameters from the Guice Injector and others from the caller: コンストラクタの一部のパラメータをGuiceによる注入とし、その他のパラメータを呼び出し側から指定したいことがある。
Line 9: Line 9:
        CreditService creditService, // from the Injector
        AuthService authService, // from the Injector
        Date startDate, // from the instance's creator
        Money amount); // from the instance's creator
        CreditService creditService, // インジェクタから
        AuthService authService, // インジェクタから
        Date startDate, // 呼び出し側から
        Money amount); // 呼び出し側から
Line 17: Line 17:
The standard solution to this problem is to write a factory that helps Guice build the objects: この問題の標準的な解決法Guiceがオブジェクトをビルドするのを助けるファクトリを記述することである。
Line 40: Line 40:
...and a corresponding binding in the module: そしてモジュール内では対応するバインディングを記述する。
Line 44: Line 44:
It's annoying to write the boilerplate factory class each time this situation arrises. It's also annoying to update the factories when the implementation class' dependencies change.
Factories by AssistedInject
このような状況が現れるその度に、ボイラープレートな(決まりきった)ファクトリクラスを書くのは面倒である。
なおかつ、実装クラスの依存が変更されるとファクトリも更新しなくてはならないのもまた面倒である。
Line 47: Line 47:
AssistedInject generates an implementation of the factory class automatically. To use it, annotate the implementation class' constructor and the fields that aren't known by the injector: == AssistedInjectによるファクトリ ==

AssistedInjectじゃファクトリクラスの実装を自動的に生成する。
使用するには、実装クラスのコンストラクタとインジェクタの知らないフィールドをアノテーションする。
Line 60: Line 63:
Then bind a Provider<Factory> in the Guice module: そして、モジュールの中でProvider<Factory>をバインドする。
Line 65: Line 68:
The FactoryProvider maps the create() method's parameters to the corresponding @Assisted parameters in the implementation class' constructor. For the other constructor arguments, it asks the regular Injector to provide values. FactoryProviderはcreate()メソッドのパラメータを、実装クラスのコンストラクタ中の対応する@Assistedパラメータにマップする。
他のコンストラクタ引数については、通常のインジェクタにその値を問い合わせる。
Line 67: Line 71:
With FactoryProvider, it's easier to create classes that need extra arguments at construction time: FactoryProviderを使えば、コンストラクタの追加引数を必要とするクラスの生成が簡単になる。
Line 69: Line 73:
 1. Annotate the constructor and assisted parameters on the implementation class (such as RealPayment)
 1. Create a factory interface with a create() method that takes only the assisted parameters. Make sure they're in the same order as in the constructor
 1. Bind that factory to a provider created by FactoryProvider.
 1. 実装クラス(RealPaymentのような)のコンストラクタとassistedパラメータをアノテーションする。
 1. assistedパラメータのみを引数とするcreate()メソッドのあるファクトリインターフェースを定義する。ただし、それらの引数順序はコンストラクタのものと同一であること。
 1. FactoryProviderを使って、ファクトリをプロバイダにバインドする。

AssistedInject

人手によるファクトリ

コンストラクタの一部のパラメータをGuiceによる注入とし、その他のパラメータを呼び出し側から指定したいことがある。

public class RealPayment implements Payment {
  public RealPayment(
        CreditService creditService,  // インジェクタから
        AuthService authService,  // インジェクタから
        Date startDate, // 呼び出し側から
        Money amount); // 呼び出し側から
  }
  ...
}

この問題の標準的な解決法Guiceがオブジェクトをビルドするのを助けるファクトリを記述することである。

public interface PaymentFactory {
  public Payment create(Date startDate, Money amount);
}

public class RealPaymentFactory implements PaymentFactory {
  private final Provider<CreditService> creditServiceProvider;
  private final Provider<AuthService> authServiceProvider;

  @Inject
  public PaymentFactory(Provider<CreditService> creditServiceProvider,
      Provider<AuthService> authServiceProvider) {
    this.creditServiceProvider = creditServiceProvider;
    this.authServiceProvider = authServiceProvider;
  }

  public Payment create(Date startDate, Money amount) {
    return new RealPayment(creditServiceProvider.get(),
      authServiceProvider.get(), startDate, amount);
  }
}

そしてモジュール内では対応するバインディングを記述する。

   bind(PaymentFactory.class).to(RealPaymentFactory.class);

このような状況が現れるその度に、ボイラープレートな(決まりきった)ファクトリクラスを書くのは面倒である。 なおかつ、実装クラスの依存が変更されるとファクトリも更新しなくてはならないのもまた面倒である。

AssistedInjectによるファクトリ

AssistedInjectじゃファクトリクラスの実装を自動的に生成する。 使用するには、実装クラスのコンストラクタとインジェクタの知らないフィールドをアノテーションする。

public class RealPayment implements Payment {
  @Inject
  public RealPayment(
        CreditService creditService,
        AuthService authService,
        @Assisted Date startDate,
        @Assisted Money amount);
  }
  ...
}

そして、モジュールの中でProvider<Factory>をバインドする。

bind(PaymentFactory.class).toProvider(
    FactoryProvider.newFactory(PaymentFactory.class, RealPayment.class));

FactoryProviderはcreate()メソッドのパラメータを、実装クラスのコンストラクタ中の対応する@Assistedパラメータにマップする。 他のコンストラクタ引数については、通常のインジェクタにその値を問い合わせる。

FactoryProviderを使えば、コンストラクタの追加引数を必要とするクラスの生成が簡単になる。

  1. 実装クラス(RealPaymentのような)のコンストラクタとassistedパラメータをアノテーションする。

  2. assistedパラメータのみを引数とするcreate()メソッドのあるファクトリインターフェースを定義する。ただし、それらの引数順序はコンストラクタのものと同一であること。
  3. FactoryProviderを使って、ファクトリをプロバイダにバインドする。