Как избежать switch-case в фабричном методе дочерних классов - PullRequest
22 голосов
/ 01 мая 2011

Допустим, у нас есть семейство классов (ради карт), и нам нужно создавать их экземпляры на основе некоторого идентификатора. Заводской метод будет выглядеть так:

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 ключа в словарь?).

Какая лучшая практика в этом сценарии?

1 Ответ

46 голосов
/ 01 мая 2011

Вместо сохранения типа в словаре, вы можете сохранить Func<Card>:

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

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

В случае карт, я бы, вероятно, сделал их неизменными для запускас и просто заполнить словарь самими карточками, но это другое дело :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...