Добрый день! Пусть есть несколько классов, например:
public class ProductA
{
public string FieldFirst { get; set; }
public string FieldSecond { get; set; }
public string FieldThird { get; set; }
public string FieldFourth { get; set; }
}
public class ProductB
{
public string FieldFirst { get; set; }
public string FieldSecond { get; set; }
public string FieldThird { get; set; }
public List FieldFourth { get; set; }
}
public class ProductC
{
public string FieldFirst { get; set; }
public string FieldSecond { get; set; }
public List FieldThird { get; set; }
}
public class ProductD
{
public string FieldFirst { get; set; }
public List FieldSecond { get; set; }
}
Собственно, хотел узнать, возможно ли сделать общий интерфейс для выбора класса и создания объекта. Нельзя ли найти какой-нибудь единый интерфейс для них, и использовать, например Абстрактную Фабрику. Или это нельзя сделать в данном случае. Заранее огромное спасибо!
Ответ
Простое решение
Если типы аргументов известны на стадии компиляции и наборы типов параметров уникальны, то можно сделать банальную фабрику:
public static class ProductFactory
{
public static ProductA Create (string fieldFirst, string fieldSecond, string fieldThird, string fieldFourth)
{
return new ProductA(fieldFirst, fieldSecond, fieldThird, fieldFourth);
}
public static ProductB Create (string fieldFirst, string fieldSecond, string fieldThird, List fieldFourth)
{
return new ProductB(fieldFirst, fieldSecond, fieldThird, fieldFourth);
}
public static ProductC Create (string fieldFirst, string fieldSecond, List fieldThird)
{
return new ProductC(fieldFirst, fieldSecond, fieldThird);
}
public static ProductD Create (string fieldFirst, List fieldSecond)
{
return new ProductD(fieldFirst, fieldSecond);
}
}
Тогда создание объектов будет выглядеть следующим образом:
ProductA productA = ProductFactory.Create("1", "2", "3", "4");
ProductD productD = ProductFactory.Create("1", new List());
Здесь я предположил следующие классы продуктов:
public class ProductA
{
public string FieldFirst { get; set; }
public string FieldSecond { get; set; }
public string FieldThird { get; set; }
public string FieldFourth { get; set; }
public ProductA (string fieldFirst, string fieldSecond, string fieldThird, string fieldFourth)
{
FieldFirst = fieldFirst;
FieldSecond = fieldSecond;
FieldThird = fieldThird;
FieldFourth = fieldFourth;
}
}
public class ProductB
{
public string FieldFirst { get; set; }
public string FieldSecond { get; set; }
public string FieldThird { get; set; }
public List FieldFourth { get; set; }
public ProductB (string fieldFirst, string fieldSecond, string fieldThird, List fieldFourth)
{
FieldFirst = fieldFirst;
FieldSecond = fieldSecond;
FieldThird = fieldThird;
FieldFourth = fieldFourth;
}
}
public class ProductC
{
public string FieldFirst { get; set; }
public string FieldSecond { get; set; }
public List FieldThird { get; set; }
public ProductC (string fieldFirst, string fieldSecond, List fieldThird)
{
FieldFirst = fieldFirst;
FieldSecond = fieldSecond;
FieldThird = fieldThird;
}
}
public class ProductD
{
public string FieldFirst { get; set; }
public List FieldSecond { get; set; }
public ProductD (string fieldFirst, List fieldSecond)
{
FieldFirst = fieldFirst;
FieldSecond = fieldSecond;
}
}
Сложное решение
Если на стадии компиляции ничего не известно, а аргументы собираются вручную во время выполнения программы, то можно воспользоваться Autofac, например. Вот пример использования, когда выбор делается на основе имён и типов параметров, и имена параметров не совпадают с именами аргументов конструктора:
var builder = new ContainerBuilder();
builder
.Register((c, p) => {
switch (p.Count()) {
case 4:
if (p.OfType().Any(a => a.Name == "str4"))
return new ProductA(
p.Named("str1"), p.Named("str2"), p.Named("str3"), p.Named("str4"));
else
return new ProductB(
p.Named("str1"), p.Named("str2"), p.Named("str3"), p.Named>("ints"));
case 3:
return new ProductC(
p.Named("str1"), p.Named("str2"), p.Named>("doubles"));
case 2:
return new ProductD(
p.Named("str1"), p.Named>("floats"));
}
throw new DependencyResolutionException("Could not resolve product.");
})
.As();
IContainer container = builder.Build();
var productA = container.Resolve(
new NamedParameter("str1", "1"),
new NamedParameter("str2", "2"),
new NamedParameter("str3", "3"),
new NamedParameter("str4", "4"));
var productD = container.Resolve(
new NamedParameter("str1", "1"),
new NamedParameter("floats", new List()));
Предполагается, что продукты реализованы следующим образом:
public interface IProduct
{}
public class ProductA : IProduct
{
public string FieldFirst { get; set; }
public string FieldSecond { get; set; }
public string FieldThird { get; set; }
public string FieldFourth { get; set; }
public ProductA (string fieldFirst, string fieldSecond, string fieldThird, string fieldFourth)
{
FieldFirst = fieldFirst;
FieldSecond = fieldSecond;
FieldThird = fieldThird;
FieldFourth = fieldFourth;
}
}
public class ProductB : IProduct
{
public string FieldFirst { get; set; }
public string FieldSecond { get; set; }
public string FieldThird { get; set; }
public List FieldFourth { get; set; }
public ProductB (string fieldFirst, string fieldSecond, string fieldThird, List fieldFourth)
{
FieldFirst = fieldFirst;
FieldSecond = fieldSecond;
FieldThird = fieldThird;
FieldFourth = fieldFourth;
}
}
public class ProductC : IProduct
{
public string FieldFirst { get; set; }
public string FieldSecond { get; set; }
public List FieldThird { get; set; }
public ProductC (string fieldFirst, string fieldSecond, List fieldThird)
{
FieldFirst = fieldFirst;
FieldSecond = fieldSecond;
FieldThird = fieldThird;
}
}
public class ProductD : IProduct
{
public string FieldFirst { get; set; }
public List FieldSecond { get; set; }
public ProductD (string fieldFirst, List fieldSecond)
{
FieldFirst = fieldFirst;
FieldSecond = fieldSecond;
}
}