4

我的问题是专门处理通过构造函数的依赖注入。我了解服务定位器模式、构造函数/设置器注入及其风格的优缺点,但是在选择纯构造函数注入后,我似乎无法克服一些问题。在阅读了许多可测试设计的材料后,包括彻底阅读 Miško Hevery 的博客(特别是这篇文章)后,我处于以下情况:

假设我正在编写一个 C++ 程序,并且我已经通过它们的构造函数正确地注入了我的依赖项。为了可读性,我给了自己一个高级对象,它有一个从 main 调用的 Execute() 函数:

int main(int argc, char* argv[]) {
    MyAwesomeProgramObject object(argc, argv);
    return object.Execute();
}

Execute() 的职责是简单地连接所有需要的对象并启动最高级别的对象。最高级别的对象需要几个依赖项,这些对象需要一些对象等等,这意味着一个看起来像这样的函数:

MyAwesomeProgramObject::Execute() {
    DependencyOne one;
    DependencyTwo two;
    DependencyThree three;

    MidLevelOne mid_one(one);
    MidLevelTwo mid_two(two, three);

    // ...

    MidLevelN mid_n(mid_dependencyI, mid_dependencyJ, mid_dependencyK);

    // ...

    HighLevelObject1 high_one(mid_one, mid_n);
    HighLevelObject2 high_two(mid_two);

    ProgramObject object(high_one, high_two);
    return object.Go();
}

从我从 Miško 的博客中获得的内容(我会问他,但认为他没有时间回复我),这是满足纯构造函数注入依赖项的唯一方法。

在提到的博客文章中,他指出我们应该在每个对象的生命周期级别上都有工厂,但这本质上是 Execute 正在做的事情,使我的代码看起来与他的示例相同:

AuditRecord audit = new AuditRecord();
Database database = new Database(audit);
Captcha captcha = new Captcha();
Authenticator authenticator =
    new Authenticator(database, captcha, audit);
LoginPage = new LoginPage(audit, authenticator);

问题:

  • 这是正确的方法吗?
  • 这是我不知道的模式吗(似乎类似于 Maven 的 context.xml)?
  • 对于纯粹的构造函数注入,我是否只是承受“前期”分配的成本?
4

1 回答 1

0

请注意,您的不同示例是矛盾的。首先,您展示了在堆栈上创建对象,最后一个示例分配对象。

堆栈上的对象有些危险,但在大多数情况下都很好。主要问题是当该对象来自堆栈时,为另一个生命周期比您的函数更长的对象提供一个对象指针......当该长期存在的对象在函数返回后尝试访问堆栈上的对象时,您有一个问题。如果所有对象都有一个堆栈生命周期,那么你很好。

就个人而言,我开始使用共享指针,我发现这是简化大量对象管理的终极方法。

std::shared_ptr<foo> foo_object(new foo);
std::shared_ptr<blah> foo_object(new blah(foo));

这样,blah 可以永久保存 foo 共享指针的副本,并且一切都按预期工作,即使在函数边界之间也是如此。不仅如此,共享指针在创建时为 NULL,并在删除时自动删除(当然,当最后一个共享指针被删除时)。您可以在不需要始终设置指针的对象中使用弱指针。 ..

否则,我认为您正在尝试做的事情在一定程度上起作用。在我的世界里,事物通常是在以后创建的,所以我需要一个二传手。但是,构造函数注入对于强制用户正确初始化您的对象非常有用(即我经常创建只读对象,没有设置器,它们在构造时 100% 初始化,非常实用,非常安全!)

于 2013-12-05T01:59:47.413 回答