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

如何通过依赖注入重构存在代码异味与循环依赖的上帝类?

重构方案:解决SRP违反、循环依赖与DI框架限制问题

核心思路

通过抽象解耦循环依赖、延迟注入解决this传递限制、拆分职责修复SRP三个步骤完成重构,同时兼容无法修改的核心库God类。


1. 抽象解耦,打破循环依赖

现有代码中PrayersSvc直接依赖God*,导致与God形成循环依赖。我们提取PrayersSvc实际需要的行为到抽象接口,让PrayersSvc依赖抽象而非具体类。

代码实现

// 自定义抽象接口:仅暴露PrayersSvc需要的方法
class ISacrificeRequester {
public:
    virtual ~ISacrificeRequester() = default;
    virtual void requestSacrifice() = 0;
};

// 修改PrayersSvc,依赖抽象接口而非God类
class PrayersSvc {
    std::unique_ptr<ISacrificeRequester> sacrificeRequester;
public:
    // 无参构造,适配DI框架初始化
    PrayersSvc() = default;

    // Setter方法用于延迟注入依赖
    void setSacrificeRequester(std::unique_ptr<ISacrificeRequester> requester) {
        sacrificeRequester = std::move(requester);
    }

    void handlePrayers(const Prayers& prayers) {
        // ... 原有业务逻辑
        sacrificeRequester->requestSacrifice();
    }
};

2. 延迟注入,解决DI框架无法传递this的问题

DI框架禁止在构造函数中传递this,我们采用先构造实例、后注入依赖的方式,利用Setter方法完成最终依赖绑定。

代码实现

// 拆分Mustang的路由职责,新建GodHandlerRouter统一处理请求转发
class GodHandlerRouter : public God {
    std::unique_ptr<PrayersSvc> prayersSvc;
    // 可扩展:添加其他服务(如SacrificeSvc等)
public:
    // 由DI框架注入PrayersSvc实例
    explicit GodHandlerRouter(std::unique_ptr<PrayersSvc> prayersSvc)
        : prayersSvc(std::move(prayersSvc)) {}

    // 用于后续注入ISacrificeRequester依赖
    void bindSacrificeRequester(ISacrificeRequester* requester) {
        prayersSvc->setSacrificeRequester(std::unique_ptr<ISacrificeRequester>(requester));
    }

    // 转发handlePrayers请求到PrayersSvc
    void handlePrayers(const Prayers& prayers) override {
        God::handlePrayers(prayers);
        prayersSvc->handlePrayers(prayers);
    }

    // 其他handle方法同理,转发到对应服务
};

// Mustang仅负责重写God的核心方法,职责单一
class Mustang : public GodHandlerRouter, public ISacrificeRequester {
public:
    // 继承父类构造函数,接收DI注入的服务
    using GodHandlerRouter::GodHandlerRouter;

    // 仅实现requestSacrifice的自定义逻辑
    void requestSacrifice() override {
        God::requestSacrifice(); // 调用核心库逻辑
        // ... 原有自定义逻辑
    }
};

3. DI框架集成示例(以Boost.DI为例)

通过工厂函数完成实例创建与依赖绑定,适配DI框架的生命周期管理:

#include <boost/di.hpp>
namespace di = boost::di;

// 工厂函数:创建Mustang并完成依赖绑定
auto createMustang() {
    // 由DI框架注入PrayersSvc实例
    auto prayersSvc = di::make_injector().create<std::unique_ptr<PrayersSvc>>();
    auto mustang = std::make_unique<Mustang>(std::move(prayersSvc));
    // 绑定Mustang自身作为ISacrificeRequester实现
    mustang->bindSacrificeRequester(mustang.get());
    return mustang;
}

重构后优势

  • 修复SRP违反:Mustang仅负责重写God的核心方法,请求路由职责由GodHandlerRouter承担,各个业务逻辑由对应服务(如PrayersSvc)实现。
  • 解除循环依赖:PrayersSvc依赖抽象接口ISacrificeRequester,不再直接依赖God类。
  • 适配DI框架:通过延迟注入避免构造函数传递this,符合DI框架的约束。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 15:27:55