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

