我对与AutoFac和抽象工厂模式相关的问题感到羞愧。我的示例是一个使用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);
}
}
服务应该通过构造函数注入来提取Factory。
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 ...
这是解决问题的正确方法吗?我不相信自己的设计,因为它在容器初始化之前强制用户输入。如果用户必须在运行时更改存储库,该怎么办?抽象工厂模式是解决这个问题的正确工具吗?
答案 0 :(得分:1)
由于在配置容器时已知存储库类型,因此应直接注册特定存储库。没有必要引入工厂,因为hardly ever is a reason引入工厂抽象。
示例:
BeerShop
此代码允许IRepository
被简化,因为its constructor would be simple现在它只取决于IRepositoryFactory
而不是IRepository
和$('.sel_item_specify').change(function(){
var getval = $(".sel_item_specify option:selected" ).val();
alert('selectbox value '+getval);
if(getval == 'other'){
$(this).closest("tr").find("button").show();
$(this).closest("tr").find("input:text").show();
$(this).closest("tr").find("input:text").attr('disabled',false);
$(this).attr('disabled','disabled');
}
else{
$(".itemremove_btn").click(function(){
$(this).hide();
$(this).closest("tr").find("input:text").attr('disabled','disabled');
$(this).closest("tr").find("select").attr('disabled',false);
});
}
});
。这简化了测试并使得更容易推理这个类。此外,它删除了不必要的抽象。
答案 1 :(得分:0)
如果要在运行时更改工厂的行为,则必须将决定正在创建的IRepository
类型的逻辑移动到工厂本身。您可以调整模式并对其进行调整以满足您的要求,而不是遵循特定的方式。
以下是一种方法,如果你考虑一下,你可以找到不同的方法来适应它。
public interface IRepository
{
//repository contracts
}
public interface IRepositoryFactory
{
IRepository Create(string arguments);
}
public interface IRepositoryBuilder
{
RepositoryType Type { get; }
IRepository Create(string args);
}
public class ApplicationSettings
{
public RepositoryType RepositoryType { get; set; }
}
public enum RepositoryType { Json, Text }
// Default implementation of repository factory based on applicationsettings.
public class ConfigurableRepositoryBuilder:IRepositoryFactory
{
private readonly ApplicationSettings _settings;
private readonly IEnumerable<IRepositoryBuilder> _repositoryBuilders;
public ConfigurableRepositoryBuilder(ApplicationSettings settings, IEnumerable<IRepositoryBuilder> repositoryBuilders)
{
_settings = settings;
_repositoryBuilders = repositoryBuilders;
}
public IRepository Create(string arguments)
{
var builder = _repositoryBuilders.First(x => x.Type == _settings.RepositoryType);
//configure builder settings and then call create
return builder.Create(arguments);
}
}
现在您可以随时更改全局设置,从下一次调用开始,您将获得新类型的存储库。您也可以从app.config或其他设置文件中读取全局单例,而不是全局单例。
您现在希望为每种受支持的IRepositoryBuilder
类型
IRepository