Является ли оператор 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;
}
Ответы
Ответ 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
Я бы не сказал его плохой дизайн, хотя он потенциально довольно жесткий. Единственный способ продлить это - перекомпиляция.