あなたが提起したように、他の答えは問題に答えました。しかし、このファクトリ メソッドで何を達成しようとしているのかを理解するために、一歩下がってみたいと思います。このファクトリは基本的に、データ型からIDataSource
パラメータへのマップを提供します。これはよく知られているデータ型と実装の小さなセットであるため (例で示されているように)、依存性注入がより適切なパターンになる可能性があります。
Widgets
すべてを Mongo に保存し、すべてGadgets
を Mysqlに保存したいとしMongoWidgetDataSource
ます。IDataSource<Widget>
MysqlGadgetDataSource
IDataSource<Gadget>
MyFactory.getDataSource(Widget.class)
データ コンシューマ内のようにファクトリ メソッド呼び出しをハードコーディングする代わりに、適切なIDataSource
依存関係を挿入します。MyService
ウィジェット(mongoに保存)で何かをするかもしれません。あなたが提案したようにファクトリを使用すると、次のようになります。
public class MyService {
public void doSomething() {
String value = MyFactory.getDataSource(Widget.class).getSomething();
// do something with data returned from the source
}
}
代わりに、適切なデータ ソースをコンストラクター引数としてサービスに挿入する必要があります。
public class MyService {
private final IDataSource<Widget> widgetDataSource;
public MyService(IDataSource<Widget> widgetDataSource) {
this.widgetDataSource = widgetDataSource;
}
public void doSomething() {
String value = widgetDataSource.getSomething();
// now do something with data returned from the source
}
}
これには、コードをより再利用可能にし、単体テスト (依存関係のモック) を容易にするという追加の利点があります。
次に、インスタンス化する場所でMyService
、データ ソースを接続することもできます。多くのプロジェクトでは、依存性注入フレームワーク ( Guiceなど) を使用してこれを簡単にしていますが、厳密な要件ではありません。ただし、個人的には、実際のサイズや期間のプロジェクトにプロジェクトなしで取り組むことはありません。
DI フレームワークを使用しない場合は、呼び出し元のサービスを作成するときに依存関係をインスタンス化するだけです。
public static void main(String[] args) {
IDataSource<Widget> widgetDataSource = new MongoWidgetDataSource();
IDataSource<Gadget> gadgetDataSource = new MysqlGadgetDataSource();
MyService service = new MyService(widgetDataSource, gadgetDataSource);
service.doSomething();
}
Guice では、これらのデータ ソースを次のように接続します。
public class DataSourceModule extends AbstractModule {
@Override
protected void configure() {
bind(new TypeLiteral<IDataSource<Widget>>() {}).to(MongoWidgetDataSource.class);
bind(new TypeLiteral<IDataSource<Gadget>>() {}).to(MysqlGadgetDataSource.class);
}
}
依存関係の逆転は、この問題についての考え方とは少し異なりますが、より分離された、再利用可能でテスト可能なコード ベースにつながる可能性があります。