2011-05-01 66 views
22

假設我們有一個類的家族(爲了它的緣故),我們需要基於某個標識符來實例化它們。 工廠方法是這樣的:如何避免子類的工廠方法中的開關盒

public Card GetCard(int cardNumber) 
{ 
    switch(cardNumber) 
    { 
    case 13: return new King(); 
    case 12: return new Queen(); 
    case 11: return new Jack();   
    } 

    //... 
} 

我想要的是避免這種switch。爲什麼?也許我想在該功能中重複使用此比較。

我來到得到的是這樣的:

private Dictionary<int, Type> cardTypes = 
{ 
    {13, typeof(King)}, 
    {12, typeof(Queen)}, 
    {11, typeof(Jack)} 
}; 

public Card GetCard(int cardNumber) 
{   
    var cardType = cardTypes[cardNumber]; 
    var instance = Activator.CreateInstance(cardType); 
    return (Card)instance; 
} 

然而,該解決方案使用了反射這是昂貴的,也是有問題的,當你有一個以上的「標識符」(例如1和14都給Ace - 我應該在字典中添加2個鍵嗎?)。

這種情況下的最佳做法是什麼?

+2

我個人認爲,如果類型的集合是固定和明顯已知和短(在人類意義上)一個工廠模式增加了很多檢修,你的第一個解決方案可以罰款足夠。如果它需要可擴展或讀取未知的未來類型或巨大的,工廠可以做。但這是最有爭議的;) – 2011-05-01 09:18:22

回答

45

而不是存儲在字典中的,你可以存儲Func<Card>

private Dictionary<int, Func<Card>> cardFactories = 
{ 
    { 13,() => new King() }, 
    // etc 
} 

public Card GetCard(int cardNumber) 
{   
    var factory = cardFactories[cardNumber]; 
    return factory(); 
} 

在卡的情況下,我可能讓他們一成不變下手,只是填充字典卡片本身,但這是另一回事:)

+0

魔術數字。裏德科普塞剛剛感覺到在力量震顫......;) – 2011-05-01 08:57:20

+2

@卡斯帕爾:是的,你當然可以使用常量代替。雖然這不是問題的關鍵,但這正是我試圖解決的問題...... – 2011-05-01 09:00:48

+0

這是一個很好的解決方案,謝謝! A.關於Ace問題呢?你會爲1和14複製Ace Func兩次嗎? B.如果每張卡需要一個參數,比如說一個「西裝」(顏色)對象,該怎麼辦?你會創建一個'Card delg(Suit)'委託,然後在字典中使用'(suit)=> new King(suit)'? – yellowblood 2011-05-01 09:02:07