Java如何实现单方法为不同玩家返回对应手牌数组
21点游戏单方法发牌逻辑重构方案
问题背景
开发21点(Blackjack)游戏时,现有代码包含Card、Deck、Player和测试类Cassino共4个类,玩家手牌由牌堆发放的卡牌组成,当前代码可正常运行,但需要仅通过1个方法实现为不同玩家返回对应卡牌数组的逻辑。
现有代码结构
- Card类:定义单张卡牌,包含点数(value)、花色(suit)两个属性
- Deck类:初始化生成包含52张卡牌的数组,内置发牌方法为玩家提供卡牌
- Player类:包含存储玩家手牌的数组属性
hands
现存问题
当前Deck类中编写了provideCards()和provideNewCards()两个逻辑完全一致的方法,分别为两位玩家返回对应的手牌数组。尝试合并方法时存在障碍:如果在方法内部新建ArrayList player = new ArrayList<>()会丢失之前已发放的手牌记录,无法在原有手牌基础上追加新卡牌,需要实现单个通用发牌方法,支持为任意玩家返回对应的手牌数组。
原有代码
Deck类代码
package jamilzin.cassino; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Random; public class Deck { private ArrayList<Card> deck = new ArrayList<>(); public ArrayList<Card> playerA = new ArrayList<>(); public ArrayList<Card> playerB = new ArrayList<>(); private ArrayList<String> suits = new ArrayList(Arrays.asList(" Diamonds", " Clubs", " Spades", " Hearts")); Random gerador = new Random(); public Deck(){ for(int j=0; j<suits.size(); j++){ // 为每个花色生成13张牌 for(int i=0; i<13; i++){ deck.add(new Card((i + 1), suits.get(j))); } } Collections.shuffle(deck); // 洗牌打乱顺序 } public ArrayList<Card> provideCards(){ int number = gerador.nextInt(52); while(deck.get(number)==null){ number = gerador.nextInt(52); } Card card = (deck.get(number)); playerA.add(card); deck.set(number, null); return playerA; } public ArrayList<Card> provideNewCards(){ int number = gerador.nextInt(52); while(deck.get(number)==null){ number = gerador.nextInt(52); } Card card = (deck.get(number)); playerB.add(card); deck.set(number, null); return playerB; } @Override public String toString(){ return deck.toString(); } }
Card类代码
package jamilzin.cassino; public class Card { private String suit; private int value; Card(int value, String suit){ this.value = value; this.suit = suit; } public String getSuit() { return suit; } public int getValue() { return value; } @Override public String toString() { return getValue() + getSuit(); } }
Player类代码
package jamilzin.cassino; import java.util.ArrayList; import java.util.List; import java.util.stream.*; public class Player { ArrayList<Card> hands = new ArrayList<>(); public Player(){ this.hands = new ArrayList<>(); } public ArrayList<Card> getHands() { return hands; } public void setHands(ArrayList<Card> hands) { this.hands = hands; } }
测试类Cassino代码
package jamilzin.cassino; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Random; import java.util.Scanner; import java.util.stream.Collectors; import java.util.stream.Stream; public class Cassino { public static void main(String[] args) { Deck deckMaster = new Deck(); Player PlayerA = new Player(); Player PlayerB = new Player(); for(int i=1;i<=5;i++){ PlayerA.setHands(deckMaster.provideCards()); } for(int i=1;i<=5;i++){ PlayerB.setHands(deckMaster.provideNewCards()); } System.out.println(PlayerA.getHands()); System.out.println(PlayerB.getHands()); System.out.println(deckMaster); } }
重构实现方案
核心思路是遵循类的职责划分:手牌本身是Player类的属性,不应该在Deck类中存储各个玩家的手牌列表。通用发牌方法只需要接收目标玩家对象作为参数,抽取的牌直接追加到传入玩家的手牌列表中即可,不需要重复编写逻辑。
重构后代码
改造Deck类
- 删除类中冗余的
playerA、playerB成员变量 - 合并两个重复发牌方法为单个
dealCard(Player targetPlayer)方法 - 优化抽牌逻辑:洗牌后直接从牌堆顶顺序抽牌,替代原有随机查找非空牌的低效逻辑
package jamilzin.cassino; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; public class Deck { private ArrayList<Card> deck = new ArrayList<>(); private ArrayList<String> suits = new ArrayList(Arrays.asList(" Diamonds", " Clubs", " Spades", " Hearts")); public Deck(){ for(int j=0; j<suits.size(); j++){ for(int i=0; i<13; i++){ deck.add(new Card((i + 1), suits.get(j))); } } Collections.shuffle(deck); } // 通用发牌方法,传入目标玩家即可完成发牌 public void dealCard(Player targetPlayer){ // 直接移除牌堆顶的第一张牌,追加到目标玩家手牌 Card drawnCard = deck.remove(0); targetPlayer.getHands().add(drawnCard); } @Override public String toString(){ return deck.toString(); } }
调整测试类调用逻辑
不需要每次发牌都调用setHands覆盖整个手牌列表,直接调用通用发牌方法传入对应玩家即可:
package jamilzin.cassino; public class Cassino { public static void main(String[] args) { Deck deckMaster = new Deck(); Player playerA = new Player(); Player playerB = new Player(); // 给玩家A发5张牌 for(int i=1;i<=5;i++){ deckMaster.dealCard(playerA); } // 给玩家B发5张牌 for(int i=1;i<=5;i++){ deckMaster.dealCard(playerB); } System.out.println("玩家A手牌:" + playerA.getHands()); System.out.println("玩家B手牌:" + playerB.getHands()); System.out.println("剩余牌堆:" + deckMaster); } }
方案优势
- 完全消除重复代码,仅用1个发牌方法就支持给任意数量玩家发牌,后续新增玩家不需要修改Deck类代码
- 职责划分清晰:Deck只负责管理牌堆、发牌,Player只负责管理自身手牌,符合面向对象设计原则
- 发牌逻辑更严谨,洗牌后顺序抽牌不会出现重复抽牌、空指针问题,执行效率高于原有随机查找逻辑
- 手牌记录不会丢失,每次发牌都是在玩家原有手牌列表上直接追加新牌
内容的提问来源于stack exchange,提问作者ffffffff
相关产品推荐
相关产品推荐

