You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 04:57:11