我想返回一个接口,在一个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;
}
答案 0 :(得分:19)
我通常不介意在工厂中使用switch语句,只要我可以对我希望工厂提前创建的所有派生类进行分组和控制。
有时,用户创建的插件可能想要将自己的类添加到该切换列表中,然后swich语句是不够的。
我发现这个好source for some more info关于创建一些更强大/多功能的工厂类
我通常采用的一种良好的中间方法是保持静态字典<字符串,类型>对于每个工厂类别。
人们可以使用某种
“注册”自己的实现Factories.TypeRegistration.StaticDictionary.Add("somekey",typeof(MyDerivedClass))
(或者更好的是,使用注册方法并隐藏StaticDictionary)
然后工厂可以通过在表中执行查找来轻松创建实例:
Activator.CreateInstance(Factories.TypeRegistration.StaticDictionary["somekey"]);
答案 1 :(得分:3)
我不知道你在c#中有哪些可能性,但是在工厂方法中使用一个开关比在整个地方使用开关更好。在工厂方法中,开关是可以容忍的 - 但最好有详细记录。
答案 2 :(得分: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框架允许您为可以基于元数据查询的接口提供多个注册。 查看this link了解MEF如何使用元数据进行导出。
答案 3 :(得分:2)
我不会说它是一个糟糕的设计,虽然它可能相当严格。扩展它的唯一方法是通过重新编译。
答案 4 :(得分:2)
我认为这没有任何问题。是的,switch语句是代码味道,但在我的书中,它们在这种情况下都可以。实际上,你无法做到这一点。
答案 5 :(得分:2)
这不错,它与“四人帮”圣经本身的一个例子(参数化工厂方法)几乎完全相同。
我以前认为switch语句是代码气味,它们不是,它们在任何OO语言中都有它们的位置。