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

如何在Boost.DI中用工厂方法替代构造函数实现自动依赖注入?

优化Boost.DI与自定义weak_ptr自持有逻辑的结合方案

针对你提到的std::shared_from_this的痛点,以及当前用Boost.DI时依赖重复声明的问题,以下是两种可行的优化方案:


方案一:利用Boost.DI的post_construct钩子(推荐)

这种方案完全贴合Boost.DI的设计理念,同时解决shared_from_this的两个核心问题:

实现步骤

  1. 把类中需要使用自身weak_ptr的初始化逻辑从构造函数中拆分到独立的init方法,构造函数仅处理常规依赖注入。
  2. 用通用辅助类统一管理自身weak_ptr的持有逻辑,避免重复代码。
  3. 在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的依赖解析能力来避免重复声明:

实现步骤

  1. 保持类的构造函数私有,保留静态New方法负责对象创建、weak_ptr初始化及业务逻辑初始化。
  2. 修改New方法,接收Boost.DI注入器实例,在方法内部通过注入器自动解析所需依赖。
  3. 在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 17:17:44