3

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.

John
  • 1,095
  • 3
  • 15
  • 31

2 Answers2

6

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.

Francis Avila
  • 31,233
  • 6
  • 58
  • 96
  • But where do I create this factory object? Should I pass it as a dependency? Preferable without static. – John Mar 27 '13 at 19:16
  • Create it before you create what needs it. – Francis Avila Mar 27 '13 at 19:35
  • Then its still tight coupled? example: public function something() { $factory = new factory(); } ? Not to speak about the setters? – John Mar 27 '13 at 19:52
  • 2
    Create it *outside* the class and pass it in, as in the example code I show above. Every program has *somewhere* where you *create* things rather than *define* things. (E.g. a `main()` method, or some method a framework calls) You can build more declarative abstractions on top, but ultimately you have to say `new Something()` somewhere! – Francis Avila Mar 27 '13 at 21:25
  • Should I make a factory for every class? The factory would be able to create all classes that objects could require. Example: class A gets FactoryA to create all object class A needs. Within FactoryA it has sub factories of every classes directly? For example FactoryA can create a config class and can be a database connection , from file etc. – John Mar 28 '13 at 12:31
  • I think you are describing a "registry" or "factoryfactory"--an object that returns other objects/factories of various types. It's better if classes don't use such a thing directly because that ties them to your registry interface. You are over-complicating things. The rule of thumb is if your class contains a `new ClassName` expression, pass it a factory *instance* instead and turn that into `$factoryObject()`. The `ClassFactory` class I wrote should cover 90% of your use cases. Closures cover 100% of them! – Francis Avila Mar 28 '13 at 13:20
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/27100/discussion-between-john-and-francis-avila) – John Mar 28 '13 at 13:47
0

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

Community
  • 1
  • 1
djheru
  • 3,525
  • 2
  • 20
  • 20
  • The factory you make where and how do you: create,define and gather the information? From the very first class that's called. – John Mar 27 '13 at 17:01
  • Seen your edit. I am stilling wondering where to create the factory object itself? – John Mar 27 '13 at 17:15