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
相关产品推荐
相关产品推荐

