具有多个类的程序中的依赖项反转(C ++)

时间:2017-10-22 18:57:49

标签: c++ dependency-injection dependency-inversion

我正在尝试将一些旧的C ++代码转换为更可测试的形式。为了符合依赖性倒置原则(DIP),我将在很多情况下使用依赖注入。

我的问题是如何最好地实例化具体类。在这段代码中有类似我自己的100个类。在他的书“清洁建筑”中,罗伯特·马丁认为这些课程是不稳定的,应该在工厂实例化。但是(参见本书第90页)这将需要我想要实例化的每个类4个类。这意味着400个班级。

让我们假设为了说明旧代码有一个A类(实例化并使用A1到A5类),B(B1到B10)和C(C1到C3类)。

在新代码中,您建议如何以及在何处实例化所有具体类?对于在大型C ++程序中处理过这类问题的人,我特别感兴趣。感谢。

布鲁斯

1 个答案:

答案 0 :(得分:1)

当应用依赖性倒置原则时,我们将协作组件(a.k.a.对象图)的图形构建延迟到最后一个负责时刻。由于我们希望最小化组件甚至单个库之间的耦合,我们将这些对象图的构造移动到系统中最不稳定的部分。这是启动装配。启动程序集中负责编写和构造这些对象图的部分通常称为Composition Root

  

在新代码中,您建议如何以及在何处实例化所有具体类?

您应该在组合根中构建所有具体的组件(包含应用程序的有趣行为的类)。

在某些托管环境中,如Java和.NET,使我们能够在运行时查询应用程序的元数据(也称为Reflection)的API的可用性允许在编译时声明抽象和实现之间的关系,以及在运行时使用可重用库动态构建的组件,通常称为 DI容器

C ++可能没有这种在运行时查询元数据的能力。在这样的环境中,您使用Pure DI,这只是意味着:您在撰写根中手动const lambdaLocal = require('lambda-local'); const AWS = require('aws-sdk'); const options = { region: 'localhost', endpoint: 'http://localhost:8000' } AWS.config.update(options); const lambda = require('./index'); describe('Item', () => { it('returns a list of items', (done) => { lambdaLocal.execute({ event: {}, lambdaFunc: lambda, lambdaHandler: 'handle', profilePath: '~/.aws/credentials', profileName: 'default', timeoutMs: 3000, callback: function(error, data) { expect(error).toBeFalsy(); expect(data).toBeTruthy(); expect(data.Count).toEqual(5); expect(data.Items[0].name).toEqual('Item name'); // ... done(); } }); }); }); 您的课程。

请注意,在我的描述中没有使用“" factory"”这个词。指定返回其他应用程序抽象的工厂抽象的需要不应该是常态,而是the exception。您可能会将Composition Root视为一个大工厂,但应用程序中的任何内容都不依赖于Composition Root。另一方面,组合根取决于一切。

因此,您的应用程序类几乎不需要依赖工厂抽象。如果一个类需要不同的服务,它应该直接将它注入到它的构造函数中,而不是注入一个可以解析该服务的工厂。