Является ли 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.

Можете ли вы описать проблему, которую вы решаете с помощью этого механизма? Скорее всего, есть более ясный способ приблизиться к нему.

редактировать

И да, код пахнет. Вы оставили комнату открытой для любого типа, за исключением того, что затем вы ограничиваете ее до одного типа и генерируете исключение во время выполнения. Зачем иметь параметр типа в этом случае?

Другие вопросы по тегам