现代C中的依赖注入与可测试性设计C 里依赖注入常常不像 Java 那样依赖庞大框架但它依然是提升可测试性和解耦能力的重要手段。核心思想很简单对象不自己偷偷创建依赖而是由外部提供。看一个紧耦合例子class DatabaseClient {public:void save() {}};class UserService {public:void create_user() {DatabaseClient db;db.save();}};这里 UserService 无法替换底层依赖测试时也很难隔离。更合理的方式是构造注入class IDatabase {public:virtual ~IDatabase() default;virtual void save() 0;};class UserService {public:explicit UserService(IDatabase db) : db_(db) {}void create_user() {db_.save();}private:IDatabase db_;};这样测试代码可以传入 fake 或 mock 实现。如果不想引入虚函数也可以采用模板或函数对象注入尤其在性能敏感路径#includetemplateclass UserServiceT {public:explicit UserServiceT(Saver saver) : saver_(std::move(saver)) {}void create_user() {saver_();}private:Saver saver_;};依赖注入的价值不只是“为了测试”更是为了显式表达边界- 这个类依赖哪些能力- 这些能力由谁提供- 生命周期由谁负责工程上要避免另一种极端为了注入而引入过多抽象层。若某个依赖稳定且无需替换简单直接也没问题。高质量设计的目标不是让每个类都抽象成接口而是让真正需要替换和隔离的边界变得可控。可测试性本质上是边界清晰度的副产品。
现代C++中的依赖注入与可测试性设计
现代C中的依赖注入与可测试性设计C 里依赖注入常常不像 Java 那样依赖庞大框架但它依然是提升可测试性和解耦能力的重要手段。核心思想很简单对象不自己偷偷创建依赖而是由外部提供。看一个紧耦合例子class DatabaseClient {public:void save() {}};class UserService {public:void create_user() {DatabaseClient db;db.save();}};这里 UserService 无法替换底层依赖测试时也很难隔离。更合理的方式是构造注入class IDatabase {public:virtual ~IDatabase() default;virtual void save() 0;};class UserService {public:explicit UserService(IDatabase db) : db_(db) {}void create_user() {db_.save();}private:IDatabase db_;};这样测试代码可以传入 fake 或 mock 实现。如果不想引入虚函数也可以采用模板或函数对象注入尤其在性能敏感路径#includetemplateclass UserServiceT {public:explicit UserServiceT(Saver saver) : saver_(std::move(saver)) {}void create_user() {saver_();}private:Saver saver_;};依赖注入的价值不只是“为了测试”更是为了显式表达边界- 这个类依赖哪些能力- 这些能力由谁提供- 生命周期由谁负责工程上要避免另一种极端为了注入而引入过多抽象层。若某个依赖稳定且无需替换简单直接也没问题。高质量设计的目标不是让每个类都抽象成接口而是让真正需要替换和隔离的边界变得可控。可测试性本质上是边界清晰度的副产品。