Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid switch-case in a factory method of child classes

Tags:

Lets say we have a family of classes (cards, for the sake of it), and we need to instantiate them based on some identifier. A factory method would look like this:

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

What I want is to avoid this switch. Why? Maybe I want to reuse this comparison in the feature.

What I came up with is something like this:

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

However, this solution uses reflection which is expensive, and is also problematic when you have more than one "identifier" (for example 1 and 14 both give Ace - should I add 2 keys to the dictionary?).

What's the best practice in this scenario?

like image 899
yellowblood Avatar asked May 01 '11 08:05

yellowblood


1 Answers

Instead of storing the type in the dictionary, you could store a Func<Card>:

private Dictionary<int, Func<Card>> cardFactories =  {     { 13, () => new King() },     // etc }  public Card GetCard(int cardNumber)  {             var factory = cardFactories[cardNumber];     return factory(); } 

In the case of cards, I'd probably make them immutable to start with and just populate the dictionary with the cards themselves, but that's a different matter :)

like image 91
Jon Skeet Avatar answered Oct 02 '22 12:10

Jon Skeet