依赖倒置原则:尝试理解
Dependency inversion principle: trying to understand
我正在学习设计模式及其周围的东西(特别是SOLID和依赖反转原理),看起来我失去了一些东西:
遵循DIP规则,我应该能够通过不在类中创建对象(composition),而是将对象引用/指针发送到类构造函数(聚合。但这意味着我必须在其他地方创建一个实例:所以一个具有聚合的类越灵活,另一个就越脆弱。
请解释我哪里错了。
您只需要遵循这个想法直到其逻辑结论。是的,你必须在其他地方创建实例,但这可能不仅仅是在比你的类高一级的类中,它一直需要被推出,直到只在应用程序的最外层创建对象。
理想情况下,您可以在一个地方创建所有对象,这被称为组合根(从工厂创建的对象除外,但工厂是在组合根中创建的)。具体位置取决于您正在构建的应用程序的类型。
- 在桌面应用程序中,这将在Main方法中(或非常接近它)
- 在ASP.NET(包括MVC)应用程序中,它将位于Global.asax
- 在WCF中,它将在ServiceHostFactory中
- 等等
这个地方最终可能会变得"脆弱",但为了能够重新配置应用程序,您只有一个地方可以更改内容,然后所有其他类都是可测试和可配置的。
看到这个优秀的答案(上面引用)
是的,您需要在某个地方实例化该类。如果你正确地遵循DIP,你最终会在一个地方创建所有的实例。我把这里称为课堂作文。阅读我的博客,更深入地了解这个主题在这里
您错过的一个重要可能性是工厂的注入,而不是类本身。这样做的一个优点是,它允许您对实例的所有权更加干净。注意,代码有点难看,因为我明确地赋予了容器组件的所有权。如果使用shared_ptr
而不是unique_ptr
,事情可能会稍微整洁一点,但所有权是模糊的。
因此,从如下代码开始:
struct MyContainer {
std::unique_ptr<IFoo> foo;
MyContainer() : foo(new Foo() ) {};
void doit() { foo->doit(); }
}
void useContainer() {
MyContainer container;
container.doit();
}
非工厂版本看起来像这个
struct MyContainer {
std::unique_ptr<IFoo> foo;
template<typename T>
explicit MyContainer(std::unique_ptr<T> && f) :
foo(std::move(f))
{}
void doit() { foo->doit(); }
}
void useContainer() {
std::unique_ptr<Foo> foo( new Foo());
MyContainer container(std::move(foo));
container.doit();
}
工厂版本看起来像
struct FooFactory : public IFooFactory {
std::unique_ptr<IFoo> createFoo() override {
return std::make_unique<Foo>();
}
};
struct MyContainer {
std::unique_ptr<IFoo> foo;
MyContainer(IFooFactory & factory) : foo(factory.createFoo()) {};
void doit() { foo->doit(); }
}
void useContainer() {
FooFactory fooFactory;
MyContainer container(fooFactory);
container.doit();
}
IMO明确表示所有权&C++中的生存期很重要-它是C++身份的关键部分-它是RAII和许多其他C++模式的核心。
相关文章:
- 如何从C++中的依赖类型中获得它所依赖的类型
- 将--whole archive链接器选项与CMake和具有其他库依赖项的库一起使用
- 将依赖名称显式标记为类型名和模板的奇怪之处
- 在 Windows 上,是否可以让 dll 在不使用 PATH 环境变量的情况下在另一个文件夹中查找依赖项?
- C++GTKMM gui循环依赖关系
- 通过ccmake在cmake中缓存依赖选项
- 当基类是依赖类型时,这是一个缺陷吗
- 从不同的附加依赖项中识别等同命名的函数
- 如何在 CMake 中对目标依赖项进行分组?
- 是否可以依赖函数范围的静态变量来执行程序关闭期间调用的方法?
- 为什么构建目录中新构建的共享库与安装目录中的副本具有不同的依赖项集?
- VS 2015 链接错误 无法构建依赖于 libcurl 的项目
- 通过依赖类型使用非类型模板参数的单类型模板参数类模板的部分专用化
- С++ wxWidgets:代码架构,设计原则和模式
- 为什么内存屏障依赖于变量?
- node-gyp 的先有鸡还是先有蛋的问题:指向依赖项中的头文件
- 反转依赖于 end() 的迭代器
- C++中的依赖反转(来自 S.O.L.I.D 原则)
- 依赖倒置原则:尝试理解
- 智能指针的依赖关系注入是否违反单一责任原则