【问题标题】:Use generics and polymorphism to enhance C# code使用泛型和多态性来增强 C# 代码
【发布时间】:2023-02-22 00:49:53
【问题描述】:

我有一个类 Deck 处理游戏中使用的 Cards。

这是基础抽象 Card 类,它只定义了每个卡值 (int):

public abstract class Card
    {
        private int value;
        protected Card(int newValue)
        {
            this.value = newValue;
        }
        public int getValue() => value;

        public void setValue(int n)
        {
            value = n;
            return;
        }

    }

一些 Card 实现:

俱乐部

 public class Club : Card
    {
        public Club(int newValue) : base(newValue)
        {
        }
    }

钻石

public class Diamond : Card
    {
        public Diamond(int newValue) : base(newValue)
        {
        }
    }

public class Heart : Card

{
    public Heart(int newValue) : base(newValue)
    {
    }
}

长钉

public class Spike : Card
    {
        public Spike(int newValue) : base(newValue)
        {
        }
    }

现在我想要在Deck 中每种类型的 10 个 Cards,总共 40 个 Cards(10 Heart,10 Spikes...)

所以我在 Deck 类中使用这段代码:

public class Deck
    {
        List<Card> cards;
        public Deck() {
            cards = new List<Card>();
            populate();
        }
        void populate()
        {
            for(int i=1;i==10;i++)
                cards.Add(new Club(i));
            for (int i = 1; i == 10; i++)
                cards.Add(new Heart(i));
            for (int i = 1; i == 10; i++)
                cards.Add(new Spike(i));
            for (int i = 1; i == 10; i++)
                cards.Add(new Diamond(i));
        }
    }

它有效,但我想要类似的东西:

void populate(){
    [Heart,Spike,Club,Diamond].foreach((e) -> cards.add(e.generateTen()))
}

我不知道这是否是正确的编写方式,请将其作为伪代码阅读我是 C# 的新手,感谢您的帮助。

【问题讨论】:

  • 旁注:C# 不是 Java - 请使用属性而不是 getXxxx/setXxxx 方法。
  • 你绝对不需要为每套牌套不同的类别。并且试图在不需要的地方设计多态性确实是一个坏主意。此外,泛型与您在此处展示的内容无关。
  • 顺便说一句,这是对多态性的一种糟糕使用。所有实现都具有相同的行为,只是它们的值不同。 Card 还不如不抽象,那样你就省了很多麻烦。
  • public enum Suit { Club, Diamond, Heart, Spade } public class Card { public Suit Suit { get; set; } public int Value { get; set; } }。这是应该做的。
  • 请注意,在 C# 中要动态创建一个数组,如 [Heart,Spike,Club,Diamond],您需要 new 关键字,并且需要指定数组类型。在上面的代码中,您没有描述 Heart、Spike、Club、Diamond 分别是什么?它们是原语、类还是其他什么?

标签: c# generics


【解决方案1】:

通常,更喜欢组合而不是多态。在这里,所有卡片实现的行为都相同。如果抽象基类的所有子类仅在构造函数上有所不同,那么也许该基类不需要是抽象的。

相反,我会推荐一种不同的方法。一张牌的花色应该是一个枚举,然后你可以这样做:

public enum Suit
{
    Heart,
    Spike,
    Club,
    Diamond
}

public class Card
{
    public Suit Suit { get; set; }
    public int Value { get; set; }
}

因为Suit现在是一个枚举,你可以用Enum.GetValues()得到所有花色的数组,所以要创建牌组:

var deck = new List<Card>();
foreach(var suit in Enum.GetValues<Suit>())
{
    for(int i = 1; i <= 10; ++i)
        deck.Add(new Card { Suit = suit, Value = i });
}

或者,如果您想真正喜欢 LINQ:

var deck = (from suit in Enum.GetValues<Suit>()
           from value in Enumerable.Range(1, 10)
           select new Card { Suit = suit, Value = value }).ToList();

【讨论】:

    【解决方案2】:

    工厂函数数组可以:

    var cards = (new Func<int, Card>[] {
        v => new Heart(v), 
        v => new Spike(v) })
        .Select(f => new {f, values = Enumerable.Range(0, 10)})
        .SelectMany(x => x.values.Select(v => x.f(v))).ToList();
    

    请注意,对于一副纸牌,您可能不会使用它,而只是将套件作为属性(因为不同的花色极不可能有不同的行为)。

    【讨论】:

      【解决方案3】:

      在 C# 中,您可以定义 enum 值,这些值是可以采用有限范围值的命名常量。一张卡片可以包含两个这样的枚举。一种用于牌套,另一种用于价值。

      public enum CardSuit
      {
          Heart = 1,
          Spike,
          Club,
          Diamond,
      }
      public enum CardValue
      {
          Ace = 1,
          Two,
          Three,
          Four,
          Five,
          Six,
          Seven,
          Eight,
          Nine,
          Ten,
          Jack,
          Queen,
          King,
      }
      
      public class Card
      {
          public Card(CardSuit suit, CardValue value)
          {
              Suit = suit;
              Value = value;
          }
      
          public CardSuit Suit { get; }
          public CardValue Value { get; }
          public int ValueInteger { get => (int)Value; }
      
          public override string ToString()
          {
              return $"[{Value} {Suit}]";
          }
      }
      

      还要注意使用属性来存储值,并且它们是只读的,因为卡值一旦定义就不会更改。

      现在定义一副牌,每套牌有 10 张牌(A 到 10)。

      public class Deck
      {
          readonly List<Card> cards;
      
          public Deck()
          {
              this.cards = new List<Card>();
      
              CardSuit[] all = new CardSuit[] {
                  CardSuit.Heart,
                  CardSuit.Spike,
                  CardSuit.Club,
                  CardSuit.Diamond };
      
              // alternative
              // var all = Enum.GetValues(typeof(CardSuit)) as CardSuit[]
              
              foreach (CardSuit suit in all)
              {
                  for (int i = 0; i < 10; i++)
                  {
                      CardValue value = (CardValue)(i + 1);
                      cards.Add(new Card(suit, value));
                  }
              }
          }
      
          public List<Card> Cards => cards;
      }
      
      static class Program
      {
          static void Main(string[] args)
          {
              var deck = new Deck();
              foreach (var card in deck.Cards)
              {
                  Console.WriteLine(card);
              }
          }
      }
      

      与输出

      [Two Heart]
      [Three Heart]
      [Four Heart]
      [Five Heart]
      [Six Heart]
      [Seven Heart]
      [Eight Heart]
      [Nine Heart]
      [Ten Heart]
      [Ace Spike]
      [Two Spike]
      [Three Spike]
      [Four Spike]
      [Five Spike]
      [Six Spike]
      [Seven Spike]
      [Eight Spike]
      [Nine Spike]
      [Ten Spike]
      [Ace Club]
      [Two Club]
      [Three Club]
      [Four Club]
      [Five Club]
      [Six Club]
      [Seven Club]
      [Eight Club]
      [Nine Club]
      [Ten Club]
      [Ace Diamond]
      [Two Diamond]
      [Three Diamond]
      [Four Diamond]
      [Five Diamond]
      [Six Diamond]
      [Seven Diamond]
      [Eight Diamond]
      [Nine Diamond]
      [Ten Diamond]
      

      【讨论】:

        猜你喜欢
        • 2010-12-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-28
        • 2014-06-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多