2011-05-01 7 views
22

Digamos que tenemos una familia de clases (tarjetas, por el bien de ellas), y tenemos que crear instancias basadas en algún identificador. Un método de fábrica sería así:Cómo evitar el switch-case en un método de fábrica de clases secundarias

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

    //... 
} 

Lo que yo quiero es evitar esta switch. ¿Por qué? Tal vez quiero reutilizar esta comparación en la función.

Lo que se me ocurrió es algo como esto:

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

Sin embargo, esta solución utiliza la reflexión, que es caro, y también es problemática cuando se tiene más de un "identificador" (por ejemplo 1 y 14 ambos dan Ace - ¿debo agregar 2 claves al diccionario?).

¿Cuál es la mejor práctica en este escenario?

+2

Personalmente creo que si la colección de tipos es Fija Y Claramente conocida Y Corta (en sentido humano) un patrón de Fábrica agrega mucha revisión, su primera solución podría estar bien suficiente. Si debe ser extensible O leer para desconocido-futuros-tipos O enorme, una fábrica podría hacer. Pero eso es muy discutible;) –

Respuesta

45

En lugar de almacenar el tipo en el diccionario, se puede almacenar un Func<Card>:

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

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

En el caso de las tarjetas, probablemente me los hago inmutable para comenzar, y acaba de llenar con el diccionario las tarjetas en sí mismas, pero esa es una cuestión diferente :)

+0

Números mágicos. Reed Copsey acaba de sentir un temblor en la fuerza ...;) –

+2

@Caspar: Sí, ciertamente podrías usar constantes. Sin embargo, ese no es realmente el punto de la pregunta, que es lo que estaba tratando de abordar ... –

+0

esta es una gran solución, ¡gracias! A. ¿Qué pasa con el problema Ace? ¿Duplicaría el Ace Func dos veces para 1 y 14? B. ¿Qué pasa si cada tarjeta necesita obtener un parámetro, por ejemplo, un objeto 'Suit' (color)? ¿Crearías un delegado de 'Card delg (Suit)' y luego usar '(suit) => new King (suit)' en el diccionario? – yellowblood

Cuestiones relacionadas