私はAutoFacと抽象的なファクトリパターンに関する問題を抱えています。 My Exampleは、IRepositoryFactoryを使用して、ユーザー入力に関連するJSONまたはInMemoryに基づいてリポジトリを作成するサービスです。オートファックを使用して抽象ファクトリの具体的な実装を切り替える
// Abstract Factory
public interface IRepositoryFactory{
IRepository Create(string databaseIdentifier);
}
// JSON
public class JsonRepositoryFactory{
public IRepository Create(string databaseIdentifier){
return new JsonRepository(databaseIdentifier);
}
}
// InMemory
public class MemoryRepository{
public IRepository Create(string databaseIdentifier){
return new MemoryRepository(databaseIdentifier);
}
}
サービスはコンストラクタインジェクションによってファクトリをプルする必要があります。
public interface IShopService{
public string Name {get;}
}
public class BeerShop : IShopService {
public string Name {get; private set;}
private readonly IRepository _repository;
public BeerShop(IRepositoryFactory repositoryFactory){
Name = "beershop";
_repository = repositoryFactory.Create(Name);
}
}
これまではこれでうまくいきます。しかし初期設定は私の好みではありません。
var builder = new ContainerBuilder();
var userInput = ReadInput();
if(userInput = "json")
builder.RegisterType<IRepositoryFactory>().As<JsonRepositoryFactory>();
else
builder.RegisterType<IRepositoryFactory>().As<MemoryRepositoryFactory>();
builder.RegisterType<IShopService>.As<BeerShop>();
var container = builder.build();
[...]
var service = container.Resolve<IShoptService>();
// and so on ...
これは正しい解決方法ですか?コンテナの初期化前にユーザー入力を強制するため、自分の設計ではわかりません。実行時にユーザーがリポジトリを変更する必要がある場合はどうなりますか?抽象的な工場パターンは、この問題を解決するための適切なツールですか?
あなたの 'BeerShop'は多すぎます:[注入コンストラクタはシンプルでなければなりません](http://blog.ploeh.dk/2011/03/03/InjectionConstructorsshouldbesimple/)。コンストラクタから 'factory.Create'への呼び出しをComposition Rootに移すと、このファクトリ抽象化はもう必要ありません。また、[工場の抽象化はコードの臭いです](https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=100)にも注意してください。 – Steven
私はStevenに同意します。あなたのクライアント(BeerShop)は、それが他のもののために同じコード/ロジックを使用するようには見えません:例:colashoop。それ以外の機会がない場合は、工場を使わないでください。工場は複雑さをもたらします。 下位レベルでこの分離が必要なようです。リポジトリは同じですが、jsonやメモリをDbとして使用します。実行時にdbを変更することは非常に危険です。あなたはjsonに何かを書いて、同じランタイムでユーザ入力によってメモリから読み込むでしょうか? –