c++中的依赖注入(Dependency Injection)是什么 如何降低代码耦合度【设计原则】

发布时间 - 2026-01-06 00:00:00    点击率:
依赖注入是通过外部传入依赖对象来解耦模块的设计方式,核心是控制反转,常用构造函数注入,配合抽象接口(如DatabaseInterface)和智能指针实现松耦合、易测试。

依赖注入是一种让类不自己创建依赖对象,而是由外部把依赖“送进来”的设计方式。它不解决具体功能问题,而是调整代码结构,让模块之间关系更松散、更易替换、更易测试。

依赖注入的核心是“控制反转”

传统写法里,一个类自己 new 依赖对象,比如:

class UserService {
    Database db;
public:
    UserService() : db("localhost") {} // 自己决定用哪个数据库
};

这样 UserService 和 Database 强绑定,换数据库就得改代码。而用依赖注入后:

class UserService {
    Database& db; // 或指针/智能指针
public:
    explicit UserService(Database& d) : db(d) {} // 依赖由外面传入
};
// 使用时:
Database mysql("192.168.1.100");
UserService service(mysql);

谁创建 Database、用 MySQL 还是 SQLite,都和 UserService 无关了——控制权从类内部转移到了外部调用者。

立即学习“C++免费学习笔记(深入)”;

三种常见注入方式(C++ 中常用)

  • 构造函数注入:最推荐。依赖在对象创建时一次性传入,状态明确、不可变,适合必需依赖。
  • Setter 注入:通过 public 成员函数设置依赖,适合可选依赖或运行时可能变更的场景(如日志输出目标)。
  • 接口注入(较少见):定义注入接口(如 Injectable),被注入类实现该接口。C++ 中因缺乏反射支持,一般不实用,多用于框架抽象层。

配合抽象接口才能真正解耦

只传具体类型(如 Database)仍不够——换数据库还得改参数类型。关键一步是依赖抽象而非实现

class DatabaseInterface {
public:
    virtual ~DatabaseInterface() = default;
    virtual void connect() = 0;
    virtual void query(const std::string&) = 0;
};

class MySQLDB : public DatabaseInterface { / 实现 / }; class SQLiteDB : public DatabaseInterface { / 实现 / };

class UserService { std::unique_ptr db; public: explicit UserService(std::unique_ptr d) : db(std::move(d)) {} };

此时 UserService 只知道“能连、能查”,完全不知道底层是 MySQL 还是 SQLite。单元测试时还能轻松注入 MockDatabase。

实际降低耦合的关键细节

  • 避免在类内部 new 具体实现类,所有 new 都应集中在少数“装配点”(如 main() 或工厂类)。
  • 使用智能指针(std::unique_ptr / std::shared_ptr)管理生命周期,避免裸指针带来的所有权模糊。
  • 依赖项尽量用 const 引用或 const 智能指针,表明只读使用,增强语义清晰度。
  • 不要为了注入而注入——简单工具类(如 MathUtils)或无状态函数通常无需 DI。


# mysql  # 工具  # ai  # c++  # red  # 成员函数  # 构造函数  # const  # 指针  # 接口  # public  # 对象  # sqlite  # database  # 数据库  # 低代码  # 更易  # 是一种  # 还能  # 是由  # 三种  # 还得  # 就得  # 可选  # 只知道  # 而非 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 开心动漫网站制作软件下载,十分开心动画为何停播?  简单实现Android验证码  如何在IIS7上新建站点并设置安全权限?  怎么用AI帮你为初创公司进行市场定位分析?  儿童网站界面设计图片,中国少年儿童教育网站-怎么去注册?  php json中文编码为null的解决办法  Laravel如何实现本地化和多语言支持_Laravel多语言配置与翻译文件管理  linux top下的 minerd 木马清除方法  网站制作软件免费下载安装,有哪些免费下载的软件网站?  CSS3怎么给轮播图加过渡动画_transition加transform实现【技巧】  iOS UIView常见属性方法小结  微信小程序 require机制详解及实例代码  动图在线制作网站有哪些,滑动动图图集怎么做?  佛山网站制作系统,佛山企业变更地址网上办理步骤?  如何快速辨别茅台真假?关键步骤解析  胶州企业网站制作公司,青岛石头网络科技有限公司怎么样?  Win11搜索栏无法输入_解决Win11开始菜单搜索没反应问题【技巧】  简单实现jsp分页  Laravel如何集成微信支付SDK_Laravel使用yansongda-pay实现扫码支付【实战】  Python文本处理实践_日志清洗解析【指导】  详解免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)  Laravel如何使用软删除(Soft Deletes)功能_Eloquent软删除与数据恢复方法  DeepSeek是免费使用的吗 DeepSeek收费模式与Pro版本功能详解  JavaScript常见的五种数组去重的方式  如何挑选最适合建站的高性能VPS主机?  如何快速启动建站代理加盟业务?  Laravel怎么处理异常_Laravel自定义异常处理与错误页面教程  jQuery 常见小例汇总  如何在橙子建站上传落地页?操作指南详解  Laravel Eloquent访问器与修改器是什么_Laravel Accessors & Mutators数据处理技巧  网站广告牌制作方法,街上的广告牌,横幅,用PS还是其他软件做的?  详解jQuery中的事件  edge浏览器无法安装扩展 edge浏览器插件安装失败【解决方法】  Laravel怎么解决跨域问题_Laravel配置CORS跨域访问  深圳网站制作培训,深圳哪些招聘网站比较好?  javascript读取文本节点方法小结  手机怎么制作网站教程步骤,手机怎么做自己的网页链接?  米侠浏览器网页背景异常怎么办 米侠显示修复  Laravel如何使用Blade模板引擎?(完整语法和示例)  如何在 Pandas 中基于一列条件计算另一列的分组均值  Laravel如何实现密码重置功能_Laravel密码找回与重置流程  怎么制作一个起泡网,水泡粪全漏粪育肥舍冬季氨气超过25ppm,可以有哪些措施降低舍内氨气水平?  如何快速查询网址的建站时间与历史轨迹?  Laravel如何使用.env文件管理环境变量?(最佳实践)  Laravel如何优化应用性能?(缓存和优化命令)  如何用美橙互联一键搭建多站合一网站?  如何快速搭建安全的FTP站点?  nodejs redis 发布订阅机制封装实现方法及实例代码  Windows10怎样连接蓝牙设备_Windows10蓝牙连接步骤【教程】  如何在 Go 中优雅地映射具有动态字段的 JSON 对象到结构体