Это статическое растение в кодекамперевере хорошо известный шаблон?

StackOverflow https://stackoverflow.com/questions/2623859

  •  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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top