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

C++多变量安全封装疑问:Blackjack游戏OOP重构是否需用Getter/Setter

Blackjack游戏C++面向对象重构:Getter/Setter的必要性与重构思路

问题背景

我正在把自己的Blackjack游戏用C++重构成面向对象风格,知道出于安全性和封装性考虑,类成员变量不应设为public,若需访问应实现Getter和Setter方法。但问题是main.cpp里频繁使用这些变量,且变量数量多,逐一实现Getter/Setter太繁琐。

现有类代码片段

Account类

class Account {
private:
    std::fstream saveFile;
public:
    std::string name;
    int tokenAmount, betAmount;

    bool doubledDown, splitted;
    bool canDoubleDown, canSplit;
    int choseToStand;

    void registerUser();
    void saveBalance();
    // [...] (constructor)
};

Hand类

class Hand {
public:
    std::vector<std::pair<std::string, std::string>> cards;
    std::pair<bool, bool> handBusted;
    int cardSum;

    void display();
    int sum();
    bool checkForBj();
};

main.cpp中直接操作类变量的代码

std::cout << "Decision: [1] Stand, [2] Hit";
if (!player.splitted && !player.doubledDown && roundNumber == 1 && player.betAmount <= player.tokenAmount) {
    std::cout << ", [3] Double down";
    player.canDoubleDown = true;
}

如果替换成Getter/Setter调用,代码会变得难以阅读,想咨询:

  1. 在此场景下是否有必要实现Getter和Setter?
  2. 若有必要,是否必须重写现有代码?

解答

1. 不是必须为所有变量写Getter/Setter

OOP的核心是封装行为而非单纯封装变量,不要为了“符合规范”而机械地给每个public变量加Getter/Setter。当前代码的问题不是变量暴露本身,而是业务逻辑散落在main函数中,类只充当了状态的容器,没有承担起对应的行为职责。

2. 正确的重构方向:把业务逻辑内聚到类中

与其硬写一堆Getter/Setter,不如把原本在main里的逻辑移到类的成员函数中,让类自己管理状态和行为:

  • 比如判断是否允许Double Down的逻辑,完全可以封装成Account类的成员函数:
    class Account {
    private:
        // 把所有状态变量设为private
        std::fstream saveFile;
        std::string name;
        int tokenAmount, betAmount;
        bool doubledDown, splitted;
        bool canDoubleDown, canSplit;
        int choseToStand;
    public:
        // 封装判断逻辑
        bool isEligibleForDoubleDown(int roundNumber) const {
            return !splitted && !doubledDown && roundNumber == 1 && betAmount <= tokenAmount;
        }
        // 提供行为方法,而非直接修改变量
        void enableDoubleDown() {
            canDoubleDown = true;
        }
        // 其他原有方法和必要的Getter/Setter
        std::string getName() const { return name; }
        void setBetAmount(int amount) {
            // 可以在这里加校验逻辑,比如不能超过tokenAmount
            if (amount > 0 && amount <= tokenAmount) {
                betAmount = amount;
            }
        }
        // [...]
    };
    
    这样main里的代码就可以简化为:
    std::cout << "Decision: [1] Stand, [2] Hit";
    if (player.isEligibleForDoubleDown(roundNumber)) {
        std::cout << ", [3] Double down";
        player.enableDoubleDown();
    }
    
  • 对于Hand类,同样可以把cards设为private,提供addCard()、getCardCount()等方法,而不是直接暴露vector;cardSum可以通过sum()方法获取,不需要直接暴露变量。

3. 何时需要Getter/Setter?

只有当外部确实需要读取某个状态,且该状态无法通过类的行为方法获取时,才需要写Getter;Setter同理,只有当外部需要修改状态,但必须经过类的校验或逻辑处理时,才需要写Setter(比如修改betAmount时检查合法性)。

4. 要不要重写现有代码?

要,但不是机械替换成Getter/Setter,而是重构逻辑,将业务行为内聚到类中。这样做的好处是:

  • 类的内部状态更安全,不会被外部随意修改导致逻辑混乱;
  • 业务逻辑集中在类中,后续维护、修改规则(比如调整Double Down的条件)时,只需要修改类的代码,不需要在main里到处找相关逻辑;
  • main函数会更简洁,只负责处理用户交互和流程控制,代码可读性反而会提升。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 02:23:16