如何在Boost.DI中用工厂方法替代构造函数实现自动依赖注入?
优化Boost.DI与自定义weak_ptr自持有逻辑的结合方案
针对你提到的std::shared_from_this的痛点,以及当前用Boost.DI时依赖重复声明的问题,以下是两种可行的优化方案:
方案一:利用Boost.DI的post_construct钩子(推荐)
这种方案完全贴合Boost.DI的设计理念,同时解决shared_from_this的两个核心问题:
实现步骤
- 把类中需要使用自身
weak_ptr的初始化逻辑从构造函数中拆分到独立的init方法,构造函数仅处理常规依赖注入。 - 用通用辅助类统一管理自身
weak_ptr的持有逻辑,避免重复代码。 - 在DI绑定中注册
post_construct钩子,确保对象被包装为shared_ptr后再初始化weak_ptr并执行业务初始化逻辑。
代码示例
#include <boost/di.hpp> #include <memory> namespace di = boost::di; // 示例依赖类 class Dep1 {}; class Dep2 {}; // 通用自身weak_ptr持有辅助类 template <typename T> class SelfWeakHolder { protected: std::weak_ptr<T> self_; public: void set_self_weak(std::weak_ptr<T> self) noexcept { self_ = std::move(self); } }; class MyClass : public SelfWeakHolder<MyClass> { public: // 构造函数仅处理常规依赖,由Boost.DI自动解析注入 MyClass(Dep1 dep1, Dep2 dep2) : dep1_(std::move(dep1)), dep2_(std::move(dep2)) {} // 安全使用self_的初始化逻辑 void init() { // 示例:将自身weak_ptr传递给其他对象 // some_external_service->register_weak_observer(self_); } private: Dep1 dep1_; Dep2 dep2_; }; int main() { auto injector = di::make_injector( di::bind<Dep1>().to<Dep1>(), di::bind<Dep2>().to<Dep2>(), di::bind<MyClass>().to<MyClass>(), // 注册post构造钩子,确保self_就绪后执行初始化 di::post_construct([](std::shared_ptr<MyClass> obj) { obj->set_self_weak(obj); obj->init(); }) ); auto my_obj = injector.create<std::shared_ptr<MyClass>>(); return 0; }
优势
- 完全保留Boost.DI的自动依赖解析能力,无需手动在绑定中声明依赖项。
- 类职责清晰:构造函数专注依赖注入,
init方法处理需要自身weak_ptr的逻辑。 - 从根源避免
shared_from_this的问题:对象必然由shared_ptr持有(DI保证),且self_在初始化时已完全有效。
方案二:结合自定义工厂方法与Boost.DI依赖解析
如果你希望保留原有的私有构造+静态工厂模式,可通过让工厂方法复用DI的依赖解析能力来避免重复声明:
实现步骤
- 保持类的构造函数私有,保留静态
New方法负责对象创建、weak_ptr初始化及业务逻辑初始化。 - 修改
New方法,接收Boost.DI注入器实例,在方法内部通过注入器自动解析所需依赖。 - 在DI绑定中通过lambda调用该
New方法,无需手动传递依赖参数。
代码示例
#include <boost/di.hpp> #include <memory> namespace di = boost::di; class Dep1 {}; class Dep2 {}; class MyClass { private: std::weak_ptr<MyClass> self_; Dep1 dep1_; Dep2 dep2_; // 私有构造函数,仅由工厂方法调用 MyClass(Dep1 dep1, Dep2 dep2) : dep1_(std::move(dep1)), dep2_(std::move(dep2)) {} // 内部初始化逻辑,使用已就绪的self_ void init() { // some_external_service->register_weak_observer(self_); } public: // 静态工厂方法,通过DI注入器自动解析依赖 static std::shared_ptr<MyClass> New(const auto& injector) { auto dep1 = injector.create<Dep1>(); auto dep2 = injector.create<Dep2>(); auto obj = std::shared_ptr<MyClass>(new MyClass(std::move(dep1), std::move(dep2))); obj->self_ = obj; obj->init(); return obj; } }; int main() { auto injector = di::make_injector( di::bind<Dep1>().to<Dep1>(), di::bind<Dep2>().to<Dep2>(), // DI绑定仅需调用工厂方法,无需重复声明依赖 di::bind<MyClass>().to([](const auto& injector) { return MyClass::New(injector); }) ); auto my_obj = injector.create<std::shared_ptr<MyClass>>(); return 0; }
优势
- 保留团队已有的工厂方法代码风格,无需大幅调整类结构。
- 依赖解析由Boost.DI自动完成,绑定代码无需随依赖变化而修改,降低维护成本。
- 确保
self_在初始化逻辑执行前完全有效,避免构造函数内调用shared_from_this的风险。
额外优化:通用工厂模板
如果多个类都需要类似的weak_ptr自持有逻辑,可以封装通用工厂模板进一步减少重复代码:
template <typename T> struct SelfWeakFactory { template <typename Injector> static std::shared_ptr<T> create(const Injector& injector) { auto obj = injector.create<std::unique_ptr<T>>(); auto shared_obj = std::shared_ptr<T>(std::move(obj)); // 要求T继承SelfWeakHolder<T> shared_obj->set_self_weak(shared_obj); shared_obj->init(); return shared_obj; } };
此时DI绑定可简化为:
di::bind<MyClass>().to(&SelfWeakFactory<MyClass>::create);
内容的提问来源于stack exchange,提问作者cds84
相关产品推荐
相关产品推荐

