0

It's my first time on StackOverflow and I hope my question isn't that noobish! I never actually tried to resolve this, I always used instead DI via setters methods instead of constructor, but It's now time to look for a better pattern! :) I tried to perform a search but I couldn't get any satisfying answer :(

Basically I have a container class that is supposed to link all the dependencies together, and every of those classes (A, B, ...) should be able to access from "their inside" other classes in the container as well.

<?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"; }
}

?>

Now that is impossible to instantiate, because MYC requires A and B, and A and B require MYC.

How can I resolve this? My professor told me that when you came into a circular dependency more than likely it's a design problem. But I can't figure out how to do it the correct way: the existence of A and B actually depends on MyCollection and vice versa.

P.S. I want to try to resolve this using DI, if it can be done in a clean and sensible way. I'm not a fan of factories! :)

Thank you in advance for your help!

MarcoR88
  • 23
  • 4

1 Answers1

2

Yeah it is a design problem.

If you wanna do it from the code you already have, you could do it like this:

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 />"; }
}

But I don't think that it's a good approach.

What are you trying to do exactly?

Maybe the observer pattern solves your particular problem?

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

now you can also change the order of the calls by the order you register your observers. Or if you want to sort it before you notify. That's up to you.

If you could provide more information or expected output it would be great.

Because I tried the first approach of code I gave you (based of your code):

$a = new A();
$b = new B();

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

or

$a = new A();
$b = new B();

$container = new MyContainer($a, $b);
$container->getA()->doSmt();
$container->getB()->doSmt();
Muqito
  • 1,369
  • 3
  • 13
  • 27
  • hi, thanks for your answer! class A must be able to call B methods from within it, and vice versa. I will add more info to the question tomorrow! thanks for now :) – MarcoR88 Jun 09 '14 at 20:46
  • Alright, but the first code block is how you can achieve that based off your code :) But you should really abstract out the common factor of the two classes (classX) and put them in a new class or something. And then have them both depend on classX instead. Since I don't understand what you're trying to achieve. I cannot really help you out more for now :) – Muqito Jun 09 '14 at 20:47
  • But you should really refactor your code and abstract out the common factor* – Muqito Jun 09 '14 at 20:53