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

如何在C++项目中实现合理封装?策略模式权限问题求解

解决策略模式中算法类访问主类私有成员的封装方案

针对你遇到的问题,核心是要在不破坏封装性的前提下,让策略类获取计算所需数据,同时避免MainClass因新增算法膨胀。下面是几种可行的干净实现方式:

方案1:为私有数据提供受控的只读接口

在MainClass中添加只读的公共方法,仅暴露策略类需要的必要数据,既满足算法需求,又能控制数据访问权限(比如只允许读取,禁止修改)。

示例代码:

// 定义策略基类
class AlgorithmStrategy {
public:
    virtual ~AlgorithmStrategy() = default;
    virtual double calculate(const std::vector<double>& numbers) = 0;
};

// 具体算法实现:平均值计算
class AverageAlgorithm : public AlgorithmStrategy {
public:
    double calculate(const std::vector<double>& numbers) override {
        double sum = 0;
        for (double num : numbers) sum += num;
        return numbers.empty() ? 0 : sum / numbers.size();
    }
};

// 具体算法实现:几何平均值计算
class GeometricMeanAlgorithm : public AlgorithmStrategy {
public:
    double calculate(const std::vector<double>& numbers) override {
        if (numbers.empty()) return 0;
        double product = 1;
        for (double num : numbers) product *= num;
        return pow(product, 1.0 / numbers.size());
    }
};

// 重构后的MainClass
class MainClass {
public:
    // 直接传入策略对象,替换原有的枚举参数
    MainClass(int something, std::unique_ptr<AlgorithmStrategy> strategy)
        : _strategy(std::move(strategy)) {
        // 初始化私有数据的逻辑示例
        _numbers = {1.2, 3.4, 5.6, 7.8};
    }

    double getResult() {
        // 通过只读接口传递数据给策略
        return _strategy->calculate(getNumbers());
    }

    // 只读接口,暴露计算所需数据
    const std::vector<double>& getNumbers() const {
        return _numbers;
    }

private:
    std::vector<double> _numbers;
    std::unique_ptr<AlgorithmStrategy> _strategy; // 持有策略实例,替代枚举
};

方案2:调用策略时直接传递数据

如果策略仅需要单次计算的数据,可以在调用策略方法时直接将_numbers作为参数传入,无需额外的访问接口。这种方式让策略类完全独立于MainClass,只依赖数据结构,解耦效果最直接。

核心修改点:

// MainClass的getResult方法
double getResult() {
    // 直接传递私有数据给策略
    return _strategy->calculate(_numbers);
}

对应的策略基类、具体算法实现与方案1一致,MainClass甚至不需要提供getNumbers()方法,结构更简洁。

方案3:重构为独立的数据上下文类

如果_numbers是算法计算的核心数据,可以将其封装为独立的DataContext类,让MainClass和策略类都依赖这个数据类,彻底避免策略对MainClass的直接依赖。

示例代码:

// 独立的数据上下文类,封装计算所需数据
class DataContext {
private:
    std::vector<double> _numbers;
public:
    DataContext(std::vector<double> numbers) : _numbers(std::move(numbers)) {}
    const std::vector<double>& getNumbers() const { return _numbers; }
    // 如需修改数据,可添加受控的修改方法
};

// 策略基类依赖DataContext
class AlgorithmStrategy {
public:
    virtual ~AlgorithmStrategy() = default;
    virtual double calculate(const DataContext& context) = 0;
};

class SumAlgorithm : public AlgorithmStrategy {
public:
    double calculate(const DataContext& context) override {
        const auto& numbers = context.getNumbers();
        double sum = 0;
        for (double num : numbers) sum += num;
        return sum;
    }
};

// 重构后的MainClass
class MainClass {
public:
    MainClass(int something, std::unique_ptr<AlgorithmStrategy> strategy)
        : _context({2.0, 4.0, 6.0}), _strategy(std::move(strategy)) {}

    double getResult() {
        return _strategy->calculate(_context);
    }

private:
    DataContext _context;
    std::unique_ptr<AlgorithmStrategy> _strategy;
};

关键注意事项

  • 替换枚举为策略对象:直接持有策略实例而非枚举类型,彻底消除switch语句,新增算法仅需实现新的策略类,完全符合开闭原则。
  • 杜绝友元依赖:友元会破坏封装性、提升类耦合度,上述方案均无需使用友元即可实现需求。
  • 保持策略独立性:策略类应仅关注算法逻辑,依赖通用数据结构而非具体业务类(如MainClass),这样策略类可复用性更强,也更容易单独测试。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 07:01:18