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

Java中如何实现Game类独有权限修改Player的cards属性?

问题解决方案与设计分析

可行解决方案

1. 将Game作为Player的静态嵌套类

利用Java嵌套类可访问外部类私有成员的特性,把Game嵌套在Player内部,让Game直接操作Player的cards属性,同时避免同包其他类访问。调整后代码如下:

public class Player {
    private List<String> cards;

    public Player(){
        cards = new ArrayList<>();
    }

    // 静态嵌套Game类,直接访问Player私有属性
    public static class Game {
        List<Player> players;

        public Game(List<Player> players){
            this.players = new ArrayList<>(players);
        }

        private void distributeCards(){
            for(Player player : players){
                player.cards.add("梅花A"); // 直接操作私有cards列表
            }
        }

        public void start(){
            distributeCards();
        }
    }
}

这种方式完全符合封装规则,代码结构清晰,也体现了Player与Game的紧密关联。

2. 包私有方法+Java模块系统限制(Java 9+)

若不想调整类嵌套结构,可给Player添加包私有方法,同时用Java 9+的模块系统限制仅Game所在模块能访问该方法,避免同包其他类(若存在)调用。

步骤1:编写Player类

package com.cardgame;

public class Player {
    private List<String> cards;

    public Player(){
        cards = new ArrayList<>();
    }

    // 包私有方法,仅同包类可见
    void receiveCard(String card) {
        cards.add(card);
    }
}

步骤2:编写Game类

package com.cardgame;

public class Game {
    List<Player> players;

    public Game(List<Player> players){
        this.players = new ArrayList<>(players);
    }

    private void distributeCards(){
        for(Player player : players){
            player.receiveCard("方块K"); // 调用包私有方法
        }
    }

    public void start(){
        distributeCards();
    }
}

步骤3:编写模块描述文件(module-info.java)

module cardgame {
    exports com.cardgame; // 对外暴露类,但包私有方法仅模块内可见
}

若模块内只有Player和Game两个类,可完全满足“仅Game可修改cards”的需求;若模块内有其他同包类,此方式无法限制,需结合其他方案。

3. 带调用者校验的方法(妥协方案)

若无法使用模块系统或嵌套类,可给Player添加一个方法,要求传入Game实例并做运行期校验,确保只有Game能调用:

public class Player {
    private List<String> cards;

    public Player(){
        cards = new ArrayList<>();
    }

    public void addCard(String card, Game caller) {
        // 运行期校验调用者身份
        if (!(caller instanceof Game)) {
            throw new IllegalArgumentException("仅Game类可调用此方法");
        }
        cards.add(card);
    }
}

Game类中调用时传入this即可:

private void distributeCards(){
    for(Player player : players){
        player.addCard("红桃Q", this);
    }
}

这种方式编译期仍允许同包其他类调用(只要传入Game实例),但能避免无意的非法调用,属于妥协方案。

4. 反射(不推荐)

通过反射可直接访问Player的私有cards属性,但会破坏封装性,且存在性能损耗、权限风险等问题,仅在极端场景下考虑:

private void distributeCards(){
    for(Player player : players){
        try {
            Field cardsField = Player.class.getDeclaredField("cards");
            cardsField.setAccessible(true);
            @SuppressWarnings("unchecked")
            List<String> cards = (List<String>) cardsField.get(player);
            cards.add("黑桃J");
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

设计原则与模式分析

  • 封装原则:嵌套类、模块系统的方案严格遵循封装原则,确保Player内部状态仅被信任的Game类修改;反射方案直接违反封装原则,不推荐。
  • 单一职责原则:所有方案都保持了Player管理自身卡片、Game负责游戏流程的职责划分,未违反该原则。
  • 设计模式:此场景无需引入特定设计模式,核心是解决访问控制问题,上述方案均属于基础的封装优化手段,未涉及复杂模式。

内容的提问来源于stack exchange,提问作者Tanvir Ahmed

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 18:46:19