Подтвердить что ты не робот

Является ли оператор switch применимым в методе factory? С#

Я хочу вернуть интерфейс и внутри оператора switch, который я хотел бы установить. Это плохой дизайн?

private IResultEntity GetEntity(char? someType)
    {
        IResultEntity entity = null;

        switch (someType)
        {
            case 'L': //life
                entity = new LifeEntity();
                break;
            case 'P': //property
                entity = new PropertyEntity();
                break;
            case 'D': //disability
                entity = new DisabilityEntity();
                break;
            case 'C': //credit card
                entity = new CreditCardEntity();
                break;
        }

        return entity;
    }
4b9b3361

Ответ 1

Я обычно не говорю о операторах switch в factory, если я могу группировать и управлять всеми производными классами, которые я хочу, чтобы мой factory создавался заранее.

Иногда, возможно, пользовательский плагин может захотеть добавить в список коммутаторов собственные классы, а затем инструкции swich недостаточно.

Я нашел этот хороший источник для дополнительной информации о создании более мощных/универсальных классов factory

Хороший подход на средней земле, который я обычно делаю, заключается в том, чтобы сохранить статический словарь < string, Тип > для каждого класса factory.

Люди могут просто "регистрировать" свои собственные реализации с помощью своего рода

Factories.TypeRegistration.StaticDictionary.Add("somekey",typeof(MyDerivedClass))

(или еще лучше использовать метод регистрации и скрыть StaticDictionary)

тогда factory имеет легкую задачу создания экземпляра путем выполнения поиска в таблице:

Activator.CreateInstance(Factories.TypeRegistration.StaticDictionary["somekey"]);

Ответ 2

Я не знаю, какие возможности у вас есть в С#, но все же лучше иметь один коммутатор в factory методе, чем переключение по всему месту. В методе factory переключатель допустим, но лучше документируйте его.

Ответ 3

Я предпочел бы тип, который вы хотите создать для определенного значения в файле конфигурации. Что-то вроде:

<TypeMappings>
< TypeMapping name =" life "type =" Entities.LifeEntity, Entities"/ >
< TypeMapping name =" property "type =" Entities.PropertyEntity, Entities"/ >
< TypeMapping name =" disability "type =" Entities.DisabilityEntity, Entities"/ >
< TypeMapping name =" creditcard "type =" Entities.CreditCardEntity, Entities "/ >
</TypeMappings>

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

Вот пример кода:

namespace Entities
{

public interface IResultEntity
{
}

public class LifeEntity : IResultEntity
{
    public override string ToString()
    {
        return("I'm a Life entity");
    }
}

public class PropertyEntity : IResultEntity
{
    public override string ToString()
    {
        return("I'm a Property Entity");
    }
}

public class CreditCardEntity : IResultEntity
{
    public override string ToString()
    {
        return("I'm a CreditCard Entity ");
    }
}

public class DisabilityEntity : IResultEntity
{
    public override string ToString()
    {
        return("I'm a Disability Entity");
    }
}

}

    public static Entities.IResultEntity GetEntity(string entityTypeName,string fileName)
{
    XDocument  doc = XDocument.Load(fileName);
    XElement element = doc.Element("TypeMappings").Elements("TypeMapping")
                               .SingleOrDefault(x => x.Attribute("name").Value == entityTypeName);        

    if(element == null)
    {
        throw new InvalidOperationException("No type mapping found for " + entityTypeName);
    }   
    string typeName = element.Attribute("type").Value;
    Type type = Type.GetType(typeName);
    Entities.IResultEntity resultEntity = Activator.CreateInstance(type) as Entities.IResultEntity;
    if(resultEntity == null)
    {
        throw new InvalidOperationException("type mapping for " + entityTypeName +  " is invalid");
    }
    return resultEntity;
}

    public static void Main()
{
    try
    {
        Entities.IResultEntity result = GetEntity("life", @"c:\temp\entities.xml");
        Console.WriteLine(result);

         result = GetEntity("property", @"c:\temp\entities.xml");
        Console.WriteLine(result);

         result = GetEntity("disability", @"c:\temp\entities.xml");
        Console.WriteLine(result);          

         result = GetEntity("creditcard", @"c:\temp\entities.xml");
        Console.WriteLine(result);          

         result = GetEntity("foo", @"c:\temp\entities.xml");
        Console.WriteLine(result);      

    }
}

Много фреймворков DI позволяют вам предоставлять несколько регистраций для интерфейса, который вы можете запросить на основе метаданных. Проверьте эту ссылку о том, как MEF экспортирует метаданные.

Ответ 4

Я не думаю, что с этим что-то не так. Да, инструкции switch - это запах кода, но в моей книге они в порядке в такой ситуации. На самом деле мало что можно сделать для достижения таких вещей.

Ответ 5

Неплохо, это почти точно так же, как пример (параметр Factory Method) в самой Библии "Банда четырех".

Раньше я думал, что операторы switch - это запах кода, а они нет, они имеют свое место на любом языке OO.

Ответ 6

Я бы не сказал его плохой дизайн, хотя он потенциально довольно жесткий. Единственный способ продлить это - перекомпиляция.