这也是我在MiškoHevery的google talks之一的评论中提出的一个问题,该评论涉及依赖注入,但它被埋没在评论中。
我想知道将依赖关系连接在一起的工厂/构建器步骤如何才能在C ++中工作。
即。我们有一个依赖于B的A类。构建器将在堆中分配B,在A的构造函数中传递指向B的指针,同时在堆中分配并返回指向A的指针。
之后谁清理?建造者在完成后清理它是否好?它似乎是正确的方法,因为在谈话中它说构建器应该设置预期具有相同生命周期的对象,或者至少依赖关系具有更长的生命周期(我也有一个问题)。我的意思是代码:
class builder {
public:
builder() :
m_ClassA(NULL),m_ClassB(NULL) {
}
~builder() {
if (m_ClassB) {
delete m_ClassB;
}
if (m_ClassA) {
delete m_ClassA;
}
}
ClassA *build() {
m_ClassB = new class B;
m_ClassA = new class A(m_ClassB);
return m_ClassA;
}
};
现在,如果有一个依赖项预计持续时间超过我们注入的对象的生命周期(比如ClassC就是依赖项)我明白我们应该将构建方法改为:
ClassA *builder::build(ClassC *classC) {
m_ClassB = new class B;
m_ClassA = new class A(m_ClassB, classC);
return m_ClassA;
}
您最喜欢的方法是什么?
答案 0 :(得分:13)
这个讲座是关于Java和依赖注入的。
在C ++中,我们尝试 NOT 传递RAW指针。这是因为RAW指针没有与之关联的所有权语义。如果您没有所有权,那么我们不知道谁负责清理对象。
我发现大部分时间依赖注入是通过C ++中的引用完成的
在极少数情况下,您必须使用指针,将它们包裹在std::unique_ptr<>或std::shared_ptr<>中,具体取决于您希望如何管理所有权。
如果您无法使用C ++ 11功能,请使用std :: auto_ptr&lt;&gt;或者boost :: shared_ptr&lt;&gt;。
我还要指出,C ++和Java编程风格现在如此不同,以至于将一种语言的风格应用于另一种语言将不可避免地导致灾难。
答案 1 :(得分:9)
这很有意思,DI在C ++中使用模板:
http://adam.younglogic.com/?p=146
我认为作者正在做出正确的举动,因为不能将字面意义上的Java DI翻译成C ++。值得一读。
答案 2 :(得分:6)
我最近被DI虫咬了。我认为它解决了很多复杂性问题,特别是自动化部分。我写了一个原型,让你以漂亮的C ++方式使用DI,或者至少我是这么认为的。您可以在此处查看代码示例:http://codepad.org/GpOujZ79
显然缺少的东西:没有范围界定,没有绑定到实现的接口。后者很容易解决,前者,我不知道。
如果有人对此代码有任何意见,我将不胜感激。
答案 3 :(得分:3)
使用RAII。
将原始指针传递给某人与交付他们的所有权相同。如果这不是你想要做的,你应该给他们某种外观,也知道如何清理有问题的对象。
的shared_ptr&LT;&GT;能做到这一点;其构造函数的第二个参数可以是一个知道如何删除对象的函数对象。
答案 4 :(得分:2)
如果你不能一劳永逸地解决所有权问题,事情会变得复杂。您只需要在实现中决定依赖项是否可能比它们注入的对象的寿命更长。
我个人会说不:注入依赖关系的对象将在之后清理。尝试通过构建器执行此操作意味着构建器必须比依赖项和注入它的对象更长寿。在我看来,这导致了比它解决的问题更多的问题,因为在完成依赖注入的构造之后,构建器不会起任何有用的作用。
答案 5 :(得分:2)
在C ++中,通常情况下,当你做得对,在大多数情况下你根本不需要编写析构函数。您应该使用智能指针自动删除内容。我认为,构建器看起来不像ClassA和ClassB实例的所有者。如果你不喜欢使用智能指针,你应该考虑对象的生命周期及其拥有者。
答案 6 :(得分:2)
根据我自己的经验,最好有明确的所有权规则。对于小型具体对象,最好使用直接复制以避免交叉依赖。
有时,交叉依赖是不可避免的,并且没有明确的所有权。例如,(m)A个实例拥有(n)个B实例,某些B实例可以由多个As拥有。在这种情况下,最好的方法是将引用计数应用于B,类似于COM引用计数。任何占有B *的函数必须首先增加引用计数,并在释放占有权时减少它。
我还避免使用boost :: shared_ptr,因为它创建了一个新类型(shared_ptr和B *成为两种不同的类型)。我发现添加方法时会带来更多麻烦。
答案 7 :(得分:1)
您还可以查看FFEAD Dependency Injection。它为Spring提供了针对JAVA的DI,并且具有非突兀的处理方式。它还有许多其他重要功能,如内置的 AJAX支持,反射,序列化,C ++解释器,C ++业务组件,ORM,消息传递,Web服务,线程池和应用程序服务器支持所有这些功能。