简体   繁体   中英

Dependency injection and/or factory pattern

Not sure if my title is correct cause I am not even sure I am using the correct terms.

I have a class that has a property that is an object. When setting this property the object has to be created. My question is how do I do this without tight coupling?

Example:

class A
{
    protected $_depending;

    protected $_somePropertyObject;

    public function __construct(\Lib\Dependency $depending)
    {
        $this->_setDepending($depending);
    }

    protected function _setDepending(\Lib\Dependency $depending)
    {
        $this->_depending = $depending;
    }

    public function setSomeProperty($someProperty)
    {
        // I want to prevent this
        $this->_somePropertyObject = new \Lib\some\Object($someProperty);
    }
}

I could just pass the required object through the construct but what happens more are needed?

When if I understand correctly the factory pattern, what would this change? I would still need to create the object somewhere? Not the object itself but the factory. Again tight coupling? Seems endless to me. When re factoring class(es) it however is isolated where and how the class(es) are made.

If I set the setSomeProperty function to only accept \\Lib\\some\\Object then is still needs to be created by the parent object that is passing it to begin with. Seems only to shift the placement of where it is created?

Hopefully I am clear enough in what I am trying to ask.

Thanks in advance!

EDIT What I am asking is the sequence of what is created when,where,why.

The purpose of a factory in dependency injection patterns is to produce instances for another instance, without that other instance needing to know how to produce it.

At its core, a "factory" is just an object-returner: something that returns an instance when invoked.

This is easier to see in more capable languages. For example in Python classes are callable (there is no new operator), and invoking a class produces an instance of the class. So classes can be their own factories if the class requires no arguments. Likewise any zero-argument function that returns an instance can be considered a factory. This makes dependency injection very clear and free-of-boilerplate.

In more rigid languages (Java/C++/C# static-typed tradition, or where classes or functions are not completely first-class like in PHP), you need to obscure dependency injection behind a "pattern", because "design patterns" are missing language features . In PHP 5.3+ you can use a closure as a factory, or you can go the Java/C# way and define a FactoryInterface and a new class per factory.

For example, with your class, you could do this:

class Aprime extends A
{
    public function setSomeProperty($somePropertyFactory)
    {
        $this->_somePropertyObject = $somePropertyFactory();
    }
}

In this class, setSomeProperty requires a zero-argument callable "factory", which you could produce like this:

$other_dep_factory = function(){ return new SomeOtherClass(); };

Or like this:

class ClassFactory {
    function __construct($classname, $args=array()) {
        $this->class = new ReflectionClass($classname);
        $this->args = $args;
    }

    function __invoke() {
        return $this->class->newInstanceArgs($this->args);
    }
}

$other_dep_factory = new ClassFactory('SomeOtherClass');

Prior to PHP 5.3, you need to do it like Java would:

interface IObjectFactory {
    function getObject();
}

// this B-and-D interface is optional
// it has no body because PHP doesn't support
// type-hinting return values
interface ISomeOtherClassFactory {}


class SomeOtherClassFactory implements ISomeOtherClassFactory {
    function getObject() {
        return new SomeOtherClass();
    }
}

class Aprime extends A
{
    public function setSomeProperty(ISomeOtherClassFactory $somePropertyFactory)
    {
        $this->_somePropertyObject = $somePropertyFactory->getObject();
    }
}


$other_dep_factory = new SomeOtherClassFactory();
$myAprimeObject->setSomeProperty($other_dep_factory);

So when do you use a factory? Whenever an object needs to create another object. If the object just needs to use another object, just pass in an instance.

I like to use the Factory Pattern when you need to collect "information" to create the object that's stored in $_somePropertyObject. For instance let's say you have to assign values to some properties to instantiate it or run a couple of methods right after you instantiate it.

Also, you'll want to consider whether you might need to later change the inheritance tree. If you might be assigning $_somePropertyObject a \\Lib\\some\\Object now, you might find yourself wishing you could easily swap it out for a \\Lib\\some\\FancyObject later. If you use Dependency Injection, you can easily swap subtypes.

Here's a primer: http://net.tutsplus.com/tutorials/php/the-whens-and-whys-for-php-design-patterns/

Also, too: https://stackoverflow.com/a/2083455/1121827

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM