web-dev-qa-db-ja.com

Guiceの@ImplementedByアノテーションの背後にある動機は何ですか?

私は最近 Google Guice で利用できる_@ImplementedBy_アノテーションについて読みました。これにより、プログラマーは、依存関係の注入で将来使用するために、インターフェースとその実装の間のバインディングを指定できます。 ジャストインタイムバインディング の例です。

次の構文を使用して、モジュールで明示的なバインディングを定義することに慣れています。

_bind(SomeInterface.class).to(SomeInterfaceImplementation.class);
_

ドキュメントによると、これは次の_@ImplementedBy_アノテーションの使用と同等です。

_@ImplementedBy(SomeInterfaceImplementation.class)
public interface SomeInterface {
    //method declarations
}
_

ここでわかる唯一の利点は、コードがわずかに短いことです。同時に、このアプローチには、同じドキュメントで正しく指摘されている欠点があります。

_@ImplementedBy_は慎重に使用してください。インターフェースからその実装にコンパイル時の依存関係を追加します。

そのような依存関係は多くの場合問題ではないかもしれませんが、私は個人的にそれをコードのにおいだと考えています。

_@ImplementedBy_アノテーションを使用する価値のあるユースケースは何ですか?

1つの可能な方法は、ライブラリまたはフレームワークのコードで使用することです。ドキュメントで説明されているように、アノテーションはdefaultバインディングを提供し、明示的なバインディングによって簡単にオーバーライドできます。

型が(最初の引数として)bind()ステートメントの両方にあり、_@ImplementedBy_注釈が付いている場合、bind()ステートメントが使用されます。アノテーションは、バインディングでオーバーライドできるデフォルトの実装を提案します。

このようにして、ライブラリの開発者として、クライアントコードのどこかでカスタマイズできるすぐに使えるバインディングをユーザーに提供できます。

これが注釈が存在する唯一の理由ですか?または私が見逃しているものはありますか?拡張するライブラリ/フレームワークではなく、いくつかのビジネスロジックを処理するアプリケーションだけのコードでそれを使用することで何かを得ることができますか?

10
toniedzwiedz

ここでの危険はonly _@ImplementedBy_アノテーションを使用していることだと思います。モジュールのbind()ステートメントなどと組み合わせて適切に使用すれば、問題ありません。

デフォルトの実装はテストに最適です。多くの依存関係があるクラスをテストするたびにモックインジェクションを明示的に定義する必要があるとは限りません。つまり、多くのものが依存しているクラスがある場合(毎回モックを定義する必要があります) )。

たとえば、次のようなクラスがあるとします。

_@ImplementedBy(NoOpDataService.class)
interface DataService {
    Map<String, MyPOJO> getData();
}
_

そしてNoOpDataServiceは:

_class NoOpDataService implements DataService {
    @Override
    public Map<String, MyPOJO> getData() {
        return Collections.emptyMap();
    }
}
_

もちろん、これを実際のコードで使用することは決してありません。 Guiceモジュールでは、実際に何かを行う実装をバインドします。ただし、DataServiceが注入されたクラスのすべてのテストでは、モックバインディングを使用する必要はありません。

tl; drあなたのインターフェースをあなたの実装に依存させることはコードの匂いになる可能性があることに同意します。ただし、定型コードを削除してテストを容易にすることもできます。機能を実装することは難しくありません。悪用の可能性は少しありますが、最終的には結果が悪くなりすぎない(サービスが突然開始される)ことがあり、たとえそれが起こったとしても、修正するのはそれほど難しくありません。

8
durron597