switch 语句是不是适用于工厂方法? C#
Posted
技术标签:
【中文标题】switch 语句是不是适用于工厂方法? C#【英文标题】:Is a switch statement applicable in a factory method? c#switch 语句是否适用于工厂方法? C# 【发布时间】:2010-11-14 21:38:55 【问题描述】:我想返回一个接口并在 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 语句,只要我可以对我希望工厂提前创建的所有派生类进行分组和控制。
有时,也许一个用户创建的插件可能想将它自己的类添加到该开关列表中,然后一个 swich 语句是不够的。
我发现这很好 source for some more info 创建一些更强大/多功能的工厂类
我通常采用的一个很好的中间方法是为每个工厂类保留一个静态 Dictionary。
人们可以使用某种方式“注册”他们自己的实现
Factories.TypeRegistration.StaticDictionary.Add("somekey",typeof(MyDerivedClass))
(或者更好的是,使用注册方法并隐藏静态字典)
那么工厂有一项简单的任务是通过在表中执行查找来创建实例:
Activator.CreateInstance(Factories.TypeRegistration.StaticDictionary["somekey"]);
【讨论】:
这就是我通常处理工厂的方式,尤其是在客户端应用可能想要添加自己的实现的库中。 更多信息链接的来源不再可用,它是否有可能被托管在其他地方?或者在某个地方有类似的帖子? @Sam Heuck 我链接了一个存档版本【参考方案2】:我不知道你在 c# 中有哪些可能性,但在工厂方法中使用一个开关仍然比到处都有开关要好。在工厂方法中,开关是可以容忍的——但最好有详细的文档记录。
【讨论】:
这个答案几乎概括了我要说的内容。我要补充一点,我在您的工厂实现中唯一要更改的是,我将使用枚举而不是可为空的字符作为工厂键。 如何将可为空的字符转换为枚举?我不认为你可以枚举字符串或字符。我认为它们代表数值。 绝对同意枚举而不是“神奇”字符。此外,如果找不到正确的大小写而不是返回 null,您可能更愿意抛出异常。我认为这可能只是一种偏好。 @Kettenbach - “如何将可为空的字符转换为枚举?”通过保留枚举值“无”【参考方案3】:我宁愿在配置文件中拥有您想要为特定值实例化的类型。 比如:
在您的方法中,您可以从配置文件中提取所有注册,找到匹配的注册并使用反射来实例化类型,如果未找到注册,则抛出异常。
这里是一些示例代码:
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 如何使用元数据进行导出。
【讨论】:
看起来有点矫枉过正【参考方案4】:我不会说这是一个糟糕的设计,尽管它可能相当僵化。扩展它的唯一方法是通过重新编译。
【讨论】:
【参考方案5】:我不认为这有什么问题。是的,switch 语句是一种代码味道,但在我的书中,它们在这种情况下是可以的。实际上,您几乎无能为力来实现这样的目标。
【讨论】:
【参考方案6】:还不错,和四人帮圣经中的一个例子(参数化工厂方法)几乎一模一样。
我曾经认为 switch 语句是一种代码味道,但事实并非如此,它们在任何 OO 语言中都占有一席之地。
【讨论】:
以上是关于switch 语句是不是适用于工厂方法? C#的主要内容,如果未能解决你的问题,请参考以下文章