Search code examples
phpoopfactorylaw-of-demeter

A factory method may violate the Law Of Demeter?


quoting from here: https://en.wikipedia.org/wiki/Law_of_Demeter

More formally, the Law of Demeter for functions requires that a method m of an object O may only invoke the methods of the following kinds of objects:[2]

  • O itself

  • m's parameters

  • Any objects created/instantiated within m

  • O's direct component objects

  • A global variable, accessible by O, in the scope of m

In particular, an object should avoid invoking methods of a member object returned by another method

so in details:

class O
{
    private $c;
    public function m($obj1)
    {
        $this->a(); // OK
        $obj1->a(); // OK
        (new C())->a(); // OK
        $c->a(); // OK
        $a = function() { };
        $a(); // OK
    }

    private function a() {}
}

now the 3rd law is questionable. So I newly created an object. But if I instead of:

(new C())->a();

I do:

$this->factory->createC()->a();

is it still valid? A regular class was instantized, just not by new but a factory. But hey! The Law said:

In particular, an object should avoid invoking methods of a member object returned by another method

by this rule, the factory method fails! Now what? Does it really fail?


Solution

  • I don't think so.

    Especially this:

    Any objects created/instantiated within m

    I would apply that to the factory as well. Even though strictly the object's constructor is called in the factory, the object is still constructed by, and especially for m. I would interpret the factory as a special kind of constructor, and look past the fact that you don't see a new keyword there.

    Given the various important roles that factories play in software design (inversion of control is one of them), I think they are too valuable to let go. It's better to change your interpretation of this law, or of what a constructor is and use those factories when you want.