Является ли StaticFactory в codecampserver хорошо известным паттерном?
ОБНОВЛЕНИЕ: это дубликат StaticFactory в codecampserver хорошо известный шаблон?
3 ответа
Изменить: Обратите внимание, что этот ответ был дан до того, как вопрос был полностью изменен при редактировании. Из-за этого он теперь относится к вещам, которые присутствовали только в вопросе, как было заявлено изначально. Прошу прощения за все "висячие указатели". :-)
Короткий ответ:
С кодом, который вы опубликовали, я не вижу альтернативы 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 интересным. Обычно их необходимо настраивать, и это включает процесс, в котором вы регистрируете конкретные типы (т.е. классы реализации) для абстрактных интерфейсов; например (здесь используется Autofac):
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.
Можете ли вы описать проблему, которую вы решаете с помощью этого механизма? Скорее всего, есть более ясный способ приблизиться к нему.
редактировать
И да, код пахнет. Вы оставили комнату открытой для любого типа, за исключением того, что затем вы ограничиваете ее до одного типа и генерируете исключение во время выполнения. Зачем иметь параметр типа в этом случае?