考虑(高度简化)以下案例:
class Dispatcher {
public:
receive() {/*implementation*/}; // callback
}
class CommInterface {
public:
send() = 0; // call
}
class CommA : public CommInterface {
public:
send() {/*implementation*/};
}
系统中的各个类通过调度程序发送消息。调度程序使用comm发送。一旦回答了答案,comm就会将其中继回调度程序,然后调度程序将其发送回适当的原始发件人。 Comm是多态的,可以从设置文件中读取要选择的实现。
Dispatcher依赖于comm以便发送。 Comm依赖于调度程序来回调。因此,这里存在循环依赖,我似乎无法实现dependency injection原则(即使在遇到this好的博客文章之后)。
更新
Comm取决于第三方代码(如 有各种第三方,Comm 是多态的)。 Comm收到了 它自己的功能,它传递它 到调度员的接收功能(在 练习有多种这样的 各种参数的功能 套)。可能的呼叫是:
CommA::receive_3(/*parameters set a*/) {
/* some parameters manipulation */
dispatcher_ptr->receive_5(/*parameters set b*/);
dispatcher_ptr->receive_6(/*parameters set c*/);
}
答案 0 :(得分:0)
如果Comm
在施工中不需要调度员,但每个send
接受调度员使用,会怎样?也就是说,
class Comm
{
virtual void send(Dispatcher *d) = 0;
};
除非Comm
由于不同的原因需要绑定到单个Dispatcher
,否则这应该消除构造时循环依赖。
答案 1 :(得分:0)
类之间的循环依赖并不总是一个问题,而且往往是不可避免的。博客所讨论的问题是,在应用依赖注入之后,构建A& B变得不可能(因为A需要B和B需要A,两者都是为了构建)。这是一种特殊的循环依赖。
如果A或B在没有另一个的情况下有意义,则避免了问题:不需要另一个的那个类可以在没有它的情况下构建。
例如,假设A是某种调度程序,它将消息发送到任意一组B对象:
struct A
{
A() {}
void add_b(B const& b) { bs.push_back(b); }
void dispatch(int num) { std::for_each(bs.begin(), bs.end(), [num](B & b) { b.message(num); }); }
void something_b_uses();
};
struct B
{
B(A* a) : my_a(a) {}
...
void message(int num) { a->something_b_uses(); }
};
有一个没有问题的循环依赖。
答案 2 :(得分:0)
我意识到,在许多类使用Dispatcher实例的情况下,只有Dispatcher实例使用CommA实例。因此,Dispatcher对CommA的依赖不应该外部化,即CommA对象不应该被“注入”Dispatcher,而不是Dispatcher中任何其他内部定义的变量。
有一分钟我认为我的问题可能会产生误导,但后来我意识到这源于对依赖注入的一个非常基本的误解。 只有在无法进行内部管理时,才应将外部化外部化。因此,我将离开这个问题和后代的答案:)
答案 3 :(得分:0)
我认为如果你为Dispatcher提供一个单独的接口类,比如你的名字约定DispatcherInterface
,那么循环依赖就应该消失了,因为现在你可以创建第三个组件(比如DispatcherCommProviderInterface
)了这个接口可以知道Comm和Dispatcher,但Comm和Dispatcher都不会知道任何关于这样的DispatcherCommProvider实现(最多他们会知道他们的接口)
接口:
// does not know anything about DispatcherCommProviderInterface or CommInterface
class DispatcherInterface {
public:
receive() = 0; // callback
}
// does not know anything about DispatcherCommProviderInterface or DispatcherInterface
class CommInterface {
public:
send() = 0; // call
}
class DispatcherCommProviderInterface {
public:
CommInterface* getComm() = 0;
DispatcherInterface* getDispatcher() = 0;
void setComm(CommInterface*) = 0;
void setDispatcher(DispatcherInterface*) = 0;
}
实现:
class CommA : public CommInterface {
public:
send() {/*implementation using some DispatcherCommProviderInterface */};
}
class Dispatcher : public DispatcherInterface {
public:
receive() {/*implementation using some DispatcherCommProviderInterface */}; // callback
}
现在你的依赖注入策略只需要创建适当的DispatcherCommProviderInterface实现(并可能将它连接到Comm和Dispatcher实例)