14.4 发牌

现在可以创建一个 Deck 对象并发牌了。下面是一个简单示例,它将 5 张牌作为玩家手中的牌,并将余下的牌作为储备牌:

  1. Deck deck = new Deck("Deck");
  2. deck.shuffle();
  3. Hand hand = new Hand("Hand");
  4. deck.deal(hand, 5);
  5. hand.display();
  6. Hand drawPile = new Hand("Draw Pile");
  7. deck.dealAll(drawPile);
  8. System.out.printf("Draw Pile has %d cards.\n",
  9. drawPile.size());

CardCollection 提供了方法 dealAll,这个方法将余下的牌都发出去。这个示例的输出如下:

  1. Hand:
  2. 5 of Diamonds
  3. Ace of Hearts
  4. 6 of Clubs
  5. 6 of Diamonds
  6. 2 of Clubs
  7. Draw Pile has 47 cards.

当然,如果你运行这个示例,得到的那手牌可能不同,因此整副牌洗得很乱。

如果你很细心,可能注意到了一些怪异的情况。我们再来看一眼方法 deal 的定义:

  1. public void deal(CardCollection that, int n) {
  2. for (int i = 0; i < n; i++) {
  3. Card card = popCard();
  4. that.addCard(card);
  5. }
  6. }

注意,第一个形参是一个 CardCollection 对象,而我们却以如下方式调用这个方法:

  1. Hand hand = new Hand("Hand");
  2. deck.deal(hand, 5);

相应的实参是一个 Hand 对象,而不是 CardCollection 对象。这种做法怎么就合法呢?这是因为 HandCardCollection 的子类,所以 Hand 对象也被视为 CardCollection 对象。如果方法需要一个 CardCollection 对象,可向它提供一个 HandDeckCardCollection 对象。

然而,反过来则不行:并非每个 CardCollection 对象都是 Hand 对象。因此,如果方法需要一个 Hand 对象,你就必须给它提供一个 Hand 对象,而不能给它提供一个 CardCollection 对象。

一个对象可以属于多种类型好像有点怪,但现实世界也存在这样的情况。所有的猫都是哺乳动物,所有哺乳动物都是动物;但并非所有的动物都是哺乳动物,并非所有的哺乳动物都是猫。