2009-07-28 70 views
12

我想返回一個接口,並在switch語句中我想設置它。這是一個糟糕的設計?switch語句是否適用於工廠方法? c#

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; 
    } 

回答

19

我通常不介意工廠中的switch語句,前提是我可以對所有派生類進行分組和控制,這些類我都希望我的工廠提前創建。

有時,也許用戶創建的插件可能希望將它自己的類添加到該切換列表,然後swich語句是不夠的。

我創造一些更強大/通用的工廠類

良好的中間路線的方法,我通常採取的是保持一個靜態字典<串類型>每個工廠類中找到這個好source for some more info。使用某種

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

人們只需「註冊」自己的實現(或更好,但使用的登錄方法和隱藏StaticDictionary)

然後工廠有一件容易的事通過在表格中執行查找來創建實例:

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

這是我通常接近工廠的方式,特別是在客戶端應用程序可能希望添加自己的實現的庫中。 – Joon 2009-07-31 07:45:47

+0

更多信息鏈接的源代碼不再可用,它被託管在其他地方的任何機會?或者在某個地方是否有相應的帖子? – 2015-05-18 14:39:51

+0

@Sam Heuck我鏈接了一個存檔版本 – Lennart 2017-02-10 09:34:48

1

我不會說它是一個糟糕的設計,雖然它可能相當嚴格。擴展這個的唯一方法是通過重新編譯。

3

我不知道你在C#中有哪些可能性,但是在工廠方法中使用一個開關比遍佈各處的開關更好。在工廠方法中,交換機是可以容忍的 - 但是更好地記錄它。

+5

這個答案几乎總結了我要說的話。 我會補充說,我會改變你的工廠實現唯一的事情是,我會使用枚舉而不是可空字符作爲工廠的關鍵。 – wtaniguchi 2009-07-28 23:55:04

+0

如何將可空字符轉換爲枚舉?我不認爲你可以做一個字符串或字符的枚舉。我認爲他們代表數字值。 – Hcabnettek 2009-07-29 00:22:00

+1

絕對同意'神奇'字符的枚舉。此外,如果找不到正確的大小寫而不是返回null,則可能更喜歡拋出異常。我認爲這可能只是一種偏好。 – kevindaub 2009-07-29 00:49:15

2

我不認爲這有什麼問題。是的,switch語句是一種代碼味道,但在我的書中,在這種情況下它們是可以的。實際上你可以做的其他事情很少,以實現這樣的事情。

3

我寧願讓你想要在配置文件中爲特定值實例化的類型。 是這樣的:

<TypeMappings>
< 名稱TypeMapping = 「生命」 類型= 「Entities.LifeEntity,實體」/ >
< 名稱TypeMapping = 「屬性」 類型= 「Entities.PropertyEntity,實體」/ >
< 名稱TypeMapping = 「殘疾」 類型= 「Entities.DisabilityEntity,實體」/ >
< 名稱TypeMapping = 「的信用卡」 類型= 「Entities.CreditCardEntity,實體」/ >
</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如何使用元數據進行導出。

+0

看起來像過度殺傷 – 2017-04-02 08:30:05

2

這並不差,它與四兄弟本身的一個例子(參數化工廠方法)幾乎完全一樣。

我曾經認爲switch語句是一種代碼味道,他們不是,他們在任何OO語言中都有自己的位置。