依赖倒置原则:试图理解

时间:2015-02-24 21:05:19

标签: c++ design-patterns aggregation composition dependency-inversion

我学习设计模式及其周围的事物(例如 SOLID 依赖性反转原则),看起来我失去了某些东西:

遵循 DIP 规则,我应该能够通过不在类中创建对象(组合)来使类更不易碎,而是将对象引用/指针发送到类构造函数(聚合)。但这意味着我必须在其他地方创建一个实例:所以聚类越灵活,另一个类就越脆弱。

请解释我哪里错了。

3 个答案:

答案 0 :(得分:5)

你只需要遵循这个想法就可以得出合乎逻辑的结论。是的,你必须在其他地方创建实例,但这可能不仅仅是在类之上的类,它需要被推出,直到只在应用程序的最外层创建对象。

理想情况下,您在一个地方创建所有对象,这称为composition root(例外是从工厂创建的对象,但工厂是在组合根中创建的)。具体取决于您正在构建的应用程序类型。

  • 在桌面应用中,它将位于Main方法中(或非常靠近它)
  • 在ASP.NET(包括MVC)应用程序中,它将在Global.asax
  • 在WCF中,这将在ServiceHostFactory

这个地方可能最终变得“脆弱”但你只有一个地方可以改变事物,以便能够重新配置你的应用程序,然后所有其他类都是可测试和可配置的。

请参阅this excellent answer(上面引用的内容)

答案 1 :(得分:0)

是的,您需要在某处实例化该类。如果您正确地遵循DIP,您将最终在一个地方创建所有实例。我称这个地方为班级作文。阅读我的博客,深入了解这一主题Here

答案 2 :(得分:0)

你错过的一个重要可能性是注入工厂,而不是课堂本身。这样做的一个优点是它允许您对实例的所有权更清晰。请注意,代码有点丑陋,因为我明确地给出了其组件的容器所有权。如果您使用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明确了所有权和&amp; C ++中的生命周期很重要 - 它是C ++身份的重要组成部分 - 它是RAII的核心和许多其他C ++模式。