2

私は現在、次のクラス/インターフェースをレイアウトしています。タイプは、実装Tから返されるデータの形式を表します。DataProviderファクトリを使用しているため、型情報を に添付する必要はありませんMyStreamingOutputHK2に注入するために使用しDataProviderFactoryていMyStreamingOutputます。

public interface DataProvider<T> {
    public T next() { ... }
    ...
}

public final class SQLDataProvider<T> {
    public SQLDataProvider(final String query, final RowMapper<T> rowMapper) { ... }
}

public interface DataProviderFactory {
    public <T> DataProvider<T> getDataProvider(final String query, final RowMapper<T> rowMapper);
    ...
}

public final class SQLDataProviderFactory {
    public <T> DataProvider<T> getDataProvider(final String query, final RowMapper<T> rowMapper) {
        return new SQLDataProvider<T>(query, rowMapper);
    }
}

public final class MyStreamingOutput implements StreamingOutput {
    public MyStreamingOutput(final DataProviderFactory dpFactory) { ... }
    @Override public void write(final OutputStream outputStream) throws IOException { ... }
}

これはすべてうまくいきます。今、私は の単体テストをセットアップしようとしMyStreamingOutputていますが、いくつかの障害に遭遇しています。テスト目的で次の追加クラスを作成しました。

public final class DataProviderFactoryStub implements DataProviderFactory {
    private final DataProvider dataProvider;

    public DataProviderFactoryStub() {
        this.dataProvider = new DataProviderStub();
    }

    public DataProviderFactoryStub(final DataProvider dataProvider) {
        this.dataProvider = dataProvider;
    }

    @Override
    public <T> DataProvider<T> getDataProvider(final String query, final RowMapper<T> rowMapper) {
        return this.dataProvider;
    }
}

バインディングは

final class QueryTestResourceConfig extends ResourceConfig {

    public QueryTestResourceConfig() {
        ...

        this.register(new AbstractBinder() {
            @Override
            protected void configure() {
                bind(DataProviderFactoryStub.class).to(DataProviderFactory.class);
            }
        });
    }

}

このクラスを に正常に挿入できますが、使用される型情報がファクトリに渡されるインスタンスによって共有されないMyStreamingOutputため、コンパイラの警告が表示されます。インターフェイスを実装しなくなるためgetDataProvider()、クラスに型情報を追加できません。間違っているため、インターフェイスの型情報は必要ありません。スタブの場合を除き、ファクトリはインスタンスによって返される型を気にする必要はありません。この場合、設計が悪いと考えているため、パラメータとパラメータにセッターを使用することは避けたいと思います。DataProviderFactoryStubDataProviderFactoryDataProviderqueryrowMapper

ジェネリックスのアプリケーションに微妙な何かが欠けているか、依存性注入のアプリケーションに明らかな何かが欠けているという感覚を揺るがすことはできません。このユースケースに対処する正しい方法は何ですか? これは DI が対処しようとしている問題のようなものですが、修正方法がわかりません。

4

2 に答える 2

1

DI を使用すると、通常、非常に基本的なファクトリ クラスになります (つまり、それらの作成メソッドは通常、1 行に収まるほど単純です)。あなたのSQLDataProviderFactoryクラスはこれの完璧な例です。

これは、ファクトリ オブジェクトがオブジェクトを作成するための単なるプレースホルダーであるためです。コードにキーワードを散らかすことは避けたいと考えてnewいます。そうすることで、コードが特定の型に密接に結び付けられるからです。newそのため、メソッドが本質的に単なる美化されたキーワードであるファクトリに行き着きます。

ここで重要なのは製品のタイプであることを指摘します。工場は単なる導管です。工場をテスト用のダブルに置き換えるとき、実際に行っていることは、製品をテスト用のダブルに置き換えることです。つまり、テスト ダブル ファクトリを定義するときは常に、テスト ダブル プロダクトも定義する必要があります。

たとえば、スタブ ファクトリが単にスタブ プロダクトを返そうとしているとします。問題は、返されるスタブ プロダクトのが、呼び出しコードで期待される型と一致しないことです。独自のスタブ プロダクトを定義すると、コードは次のようになります。

public final class DataProviderStub<T> implements DataProvider<T> {
    private final T dummy;
    public DataProviderStub() { }
    public T next() { return this.dummy; } // Just for example
}

public final class DataProviderFactoryStub implements DataProviderFactory {
    public DataProviderFactoryStub() { }

    @Override
    public <T> DataProvider<T> getDataProvider(final String query, final RowMapper<T> rowMapper) {
        return new DataProviderStub<T>();
    }
}

スタブ ファクトリは存在するだけなので、スタブDataProviderを SUT に挿入できます。

于 2014-04-28T18:53:38.293 に答える