摆脱构造函数循环依赖

时间:2014-06-09 20:05:47

标签: php oop design-patterns circular-dependency circular-reference

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

基本上我有一个容器类,它应该将所有依赖项链接在一起,并且每个类(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,反之亦然。

P.S。我想尝试使用DI解决这个问题,如果它可以以干净和明智的方式完成。我不是工厂的粉丝! :)

提前感谢您的帮助!

1 个答案:

答案 0 :(得分:2)

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

如果你想从你已有的代码中做到这一点,你可以这样做:

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();