Это статическое растение в кодекамперевере хорошо известный шаблон?
-
26-09-2019 - |
Вопрос
Обновление: это дубликатЭто статическое растение в кодекамперевере хорошо известный шаблон?
Решение
Редактировать: Обратите внимание, что этот ответ был дан до того, как вопрос был полностью изменен в редактировании. Из-за этого сейчас относится к вещам, которые присутствовали только в вопросе, как изначально заявлено. Прошу прощения за всех «висящих указателей». :-)
Краткий ответ:
С указанным вами кодом, я не вижу альтернативы литью IFoo<T>
. Отказ Если вы этого не сделаете, компилятор даст предупреждение (по крайней мере, на моей машине).
Более сложный ответ:
Ваш код действительно должен быть таким? Более конкретно, вам нужен вопрос о возмещении в первую очередь?
Я предполагаю, что вы собираетесь позвонить вашему фабричному методу более или менее, подобные этому:
var stringFoo = FooFactory.CreateFoo<string>();
Вы должны предоставить параметр шаблона (string
В этом случае) явно потому, что он не может быть получен из любого аргумента метода (в этом случае, потому что на самом деле нет вообще). Очевидно, что фабричный метод вернет IFoo<string>
.
Теперь, поскольку вы должны явно указать тип во время выполнения, вы можете просто написать:
var stringFoo = StringFoo.Create();
и поэтому иметь фабричный способ внутри StringFoo
, Вроде этого, что безоговорочно делает очевидное:
public class StringFoo : IFoo<string>
{
...
public static StringFoo Create() // or alternatively, return an IFoo<string>
{
return new StringFoo();
}
}
Применяя этот шаблон к другому IFoo<T>
Реализации тоже это сэкономит вам if
цепь или switch
блок внутри FooFactory.CreateFoo<T>
, сделайте свой код проще, и избавьтесь от необходимости, чтобы изгнать (что вы беспокоитесь).
Не поймите меня неправильно, я знаю, что фабричные методы поддерживают более одного типа объекта являются полезно в некоторых случаях; Но кажется, что в вашем случае это вызывает больше неприятностей, чем стоит.
PS: Вы можете найти один аспект некоторых контейнеров IOC. Обычно они должны быть настроены, и это охватывает процесс, в котором вы регистрируете бетонные типы (т.е. классы реализации) для абстрактных интерфейсов; Например (здесь используют Автовак):
var builder = new ContainerBuilder();
builder.RegisterType<StringFoo>().As<IFoo<string>>();
Позже вы можете запросить экземпляр объекта абстрактного типа:
using (var container = builder.Build())
{
var stringFoo = container.Resolve<IFoo<string>>();
...
}
То Resolve
Метод - это интересная часть. Вы предоставляете его абстрактным типом, и используете зарегистрированные типы, он вернет конкретный объект типа StringFoo
. Отказ Посмотрите в это, если это не звучит как навыки! :-)
Другие советы
Можете ли вы описать проблему, которую вы решаете с этим механизмом? Скорее всего, более четкий способ подойти к нему.
Редактировать
И да, код пахнет. Вы оставили открытую комнату для любого типа, за исключением того, что вы ограничите его обратно к одному типу и генерируете исключение времени выполнения. Почему параметр типа в этом случае?
Вы можете попробовать что-то вроде этого ...
public static class FooFactory
{
private static readonly Dictionary<Type, Type> FooTypesLookup;
static FooFactory()
{
FooTypesLookup = (from type in typeof(FooFactory).Assembly.GetExportedTypes()
let fooInterface =
type.GetInterfaces().FirstOrDefault(
x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IFoo<>))
where fooInterface != null
let firstTypeArgument = fooInterface.GetGenericArguments().First()
select new { Type = type, TypeArgument = firstTypeArgument })
.ToDictionary(x => x.TypeArgument, x => x.Type);
}
public static IFoo<T> CreateFoo<T>()
{
var genericArgumentType = typeof(T);
Type closedFooType;
return FooTypesLookup.TryGetValue(genericArgumentType, out closedFooType)
? (IFoo<T>) Activator.CreateInstance(closedFooType)
: null;
}
}
Или еще лучше, представьте свой любимый контейнер IOC (Windsor, карта структуры и т. Д.) и регистрируйте все типы, которые внедряют IFOO, а затем разрешать их при необходимости на месте Activator.createInstance Call.