C++向接收多接口引用构造函数传入多继承实现类的优化方案
更优实现方案
你当前三次传入*this的写法在C++语法层面是完全合法的,编译器会自动完成不同基类子对象的指针偏移转换,问题只在于代码冗余、可读性差。以下两种方案都可以在完全保留你「支持Mock测试」「限制Employee访问权限」两个设计目标的前提下,优化传参逻辑:
方案1:定义聚合依赖的门面接口
这是最贴合接口隔离原则的实现方式:先保留三个独立的细粒度接口,额外定义一个聚合了三个接口的依赖门面接口,从根源上减少传参次数。
// 原有三个细粒度接口保持不变,支持单独Mock class iperson { public: virtual void doSomething1() = 0; virtual ~iperson() = default; // 记得给纯虚接口加虚析构,避免资源泄漏 }; class imachine { public: virtual void doSomething2() = 0; virtual ~imachine() = default; }; class ibook { public: virtual void doSomething3() = 0; virtual ~ibook() = default; }; // 新增聚合接口,专门给Employee做依赖声明 class IEmployeeDependencies : public iperson, public imachine, public ibook {}; // Manager继承聚合接口,原有业务实现完全不需要修改 class Manager: public IEmployeeDependencies { public: void doSomething1() override {/** implemetation **/} void doSomething2() override {/** implemetation **/} void doSomething3() override {/** implemetation **/} void SomeBusinessFunc() { // 构造Employee只需要传一次*this Employee employee(*this); } }; // Employee构造函数改为接收聚合接口,内部依然按细粒度接口持有依赖 class Employee { private: iperson& person_impl; imachine& machine_impl; ibook& book_impl; public: Employee(IEmployeeDependencies& deps) : person_impl(deps), machine_impl(deps), book_impl(deps) // 自动转换为对应基类引用 {} };
这个方案的优势很明显:
- 不破坏原有设计:测试时既可以单独Mock三个细粒度接口,也可以直接Mock聚合接口;Employee内部只能访问三个接口定义的方法,完全接触不到Manager的其他成员
- 传参逻辑极简,没有冗余代码
- 后续如果要调整Employee的依赖,只需要修改聚合接口的定义,不需要改动所有构造Employee的传参代码
方案2:封装依赖获取的辅助方法
如果不想新增聚合接口,也可以把三次基类转换的逻辑收敛到Manager内部的辅助方法里,避免在业务代码里重复写三次*this:
class Manager: public iperson, public imachine, public ibook { private: // 内部定义依赖打包结构 struct EmployeeDeps { iperson& person_ref; imachine& machine_ref; ibook& book_ref; }; // 封装转换逻辑,对外只暴露一个获取依赖的入口 EmployeeDeps GetEmployeeDeps() { return {*this, *this, *this}; } public: void doSomething1() override {/** implemetation **/} void doSomething2() override {/** implemetation **/} void doSomething3() override {/** implemetation **/} void SomeBusinessFunc() { auto deps = GetEmployeeDeps(); Employee employee(deps.person_ref, deps.machine_ref, deps.book_ref); // C++17及以上版本可以用结构化绑定简化写法: // auto [p, m, b] = GetEmployeeDeps(); // Employee employee(p, m, b); } };
这个方案改动量极小,把重复的转换逻辑收敛到一处,后续如果接口有调整,只需要修改GetEmployeeDeps方法即可,不需要散改所有构造Employee的位置。
内容的提问来源于stack exchange,提问作者omar mossa
相关产品推荐
相关产品推荐

