Является ли StaticFactory в codecampserver хорошо известным паттерном? - PullRequest

Ответы [ 3 ]

0 голосов
/ 12 апреля 2010

Редактировать: Обратите внимание, что этот ответ был дан до того, как вопрос был полностью изменен при редактировании. Из-за этого он теперь относится к вещам, которые присутствовали только в вопросе, как было заявлено изначально. Прошу прощения за все "висячие указатели". : -)


Краткий ответ:

С кодом, который вы опубликовали, я не вижу альтернативы приведению к 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>, упростит ваш код и избавит от необходимости выполнять приведение (которое вы обеспокоены).

Не поймите меня неправильно, я знаю, что фабричные методы, поддерживающие более одного типа объекта , в некоторых случаях полезны; но, похоже, в вашем случае это вызывает больше проблем, чем стоит.


P.S.: Вам может быть интересен один аспект некоторых контейнеров 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. Посмотрите на это, если это не звучит как излишнее для вас! : -)

0 голосов
/ 12 апреля 2010

Вы можете попробовать что-то вроде этого ...

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.

0 голосов
/ 12 апреля 2010

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

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

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

...