摆脱构造函数循环依赖


getting rid of constructor circular dependency

这是我第一次在StackOverflow上,我希望我的问题不是那么无聊!我从来没有真正尝试解决这个问题,我总是使用DI通过setter方法而不是构造函数,但现在是时候寻找一个更好的模式了!:)我试着执行一个搜索,但我不能得到任何满意的答案:(

基本上我有一个容器类,应该链接所有的依赖在一起,每一个类(a, B,…)应该能够从"他们的内部"在容器中的其他类访问。

<?php
class MyContainer
{
    function __construct(A $a, B $b){
        $this->a = $a;
        $this->b = $b;
    }
    function getA(){ return $this->a; }
    function getB(){ return $this->b; }
}
class A
{
    function __construct(MyContainer $myc){ $this->myc = $myc; }
    function useA(){ echo "A"; $this->myc->getB()->doSmt(); }
    function doSmt(){ echo "A smt"; }
}
class B
{
    function __construct(MyContainer $myc){ $this->myc = $myc; }
    function useB(){ echo "B"; $this->myc->getA()->doSmt(); }
    function doSmt(){ echo "B smt"; }
}
?>

现在不可能实例化,因为MYC需要A和B,而A和B需要MYC。

如何解决这个问题?我的教授告诉我,当你遇到循环依赖时,很可能是设计问题。但我不知道如何正确地做到这一点:A和B的存在实际上取决于MyCollection,反之亦然。

注:我想尝试解决这个使用DI,如果它可以在一个干净和明智的方式。我不喜欢工厂!:)

提前感谢您的帮助!

是的,这是一个设计问题。

如果你想从你已有的代码中执行,你可以这样做:

class MyContainer
{
    function __construct(A $a, B $b){
        $a->setContainer($this);
        $b->setContainer($this);
        $this->a = $a;
        $this->b = $b;
    }
    function getA(){ return $this->a; }
    function getB(){ return $this->b; }
}
class A
{
    function setContainer(MyContainer $myc){ $this->myc = $myc; }
    function useA(){ echo "A: "; $this->myc->getB()->doSmt();echo "<br />"; }
    function doSmt(){ echo "A smt<br />"; }
}
class B
{
    function setContainer(MyContainer $myc){ $this->myc = $myc; }
    function useB(){ echo "B: "; $this->myc->getA()->doSmt();echo "<br />"; }
    function doSmt(){ echo "B smt<br />"; }
}

但我不认为这是一个好方法。

你到底想干什么?

也许观察者模式可以解决您的特定问题?

<?php
interface IObserver {
    function doSmt();
}
class Notifier{
    private $_observers = array();
    function register(IObserver $observer) {
        $this->_observers[] = $observer;
    }
    function notify() {
        foreach($this->_observers AS $observer) {
            $observer->doSmt();
        }
    }
}
class A implements IObserver {
    function doSmt() {
        echo "A smt<br />";
    }
}
class B implements IObserver {
    function doSmt() {
        echo "B smt<br />";
    }
}

$a = new A();
$b = new B();
$notifier = new Notifier();
$notifier->register($a);
$notifier->register($b);
$notifier->notify();

现在您还可以通过注册观察者的顺序来更改调用的顺序。或者你想在通知之前整理一下。这取决于你。

如果你能提供更多的信息或预期的输出,那就太好了。

因为我尝试了我给你的代码的第一种方法(基于你的代码):

$a = new A();
$b = new B();
$container = new MyContainer($a, $b);
$container->getA()->useA();
$container->getB()->useB();

$a = new A();
$b = new B();
$container = new MyContainer($a, $b);
$container->getA()->doSmt();
$container->getB()->doSmt();