2

Lighten a specific aspect of:
Factory Pattern. When to use factory methods?

At my team there was a discussion about the factory design pattern.

In our project we have some Factories that are build like this one:

class ProductFactory {

    const PRODUCT_A = 'product_a';
    const PRODUCT_B = 'product_b';
    const PRODUCT_C = 'product_c';

    private static $classMapping = array(self::PRODUCT_A => 'A',
                                         self::PRODUCT_B => 'B',
                                         self::PRODUCT_C => 'C');

    public function create($productConstant) {
        $className = self::$classMapping[$productConstant];
        return new $className();
    }
}

The discussion was about the use of this factory. If I never define a product dynamically and always define the product I like to recive from it, is there any need to use this pattern?

Community
  • 1
  • 1
  • You can change later on what the product is in concrete, without changing much code. – hakre Oct 26 '12 at 13:06
  • Just on a side note: If I'm not completely mistaken, you wouldn't instantiate ProductFactory. Therefore, it would need 'create' to be a static method (`public static function create()`). – ExternalUse Oct 26 '12 at 13:06
  • 3
    @ExternalUse: Please do not suggest that. Thank you! You want to replace the factory later on (e.g. for test-systems) and then static kills all this. Needlessly. If you're fair with your own judgement, you wouldn't have suggested a global function, would have you? – hakre Oct 26 '12 at 13:07

2 Answers2

3

The advantage of factories is that they decouple code. Take your class Foo, which needs an instance of A:

class Foo {

    public function __construct() {
        $a = new A;
    }

}

The class Foo is now coupled to the class A, because it hardcodes the classname in its source. You cannot provide an alternative implementation of A to Foo if you wanted to, for example to mock A in tests. Here's where factories come in:

class Foo {

    public function __construct(ProductFactory $factory) {
        $a = $factory->create($factory::PRODUCT_A);
    }

}

You can now inject any kind of A into Foo when needed, you have decoupled the two classes.

That's what factories are for. Use them when appropriate. If there's no problem coupling Foo to A, more power to you.

deceze
  • 510,633
  • 85
  • 743
  • 889
  • If you use Dependency Injection to inject the factory, but still pass in $factory::PRODUCT_A you aren't really decoupling anything...You are only changing the manner that A gets instantiated, for this to be effective, there would have to be some sort of mechanism to determine which product needed to be instantiated. That's my take, interested to hear your thoughts – frosty Oct 26 '12 at 13:25
  • @frosty Why? You can pass an entirely different `$factory` which returns an entirely different object when called with `create($factory::PRODUCT_A)`. That constant/parameter doesn't preclude polymorphism in any way. All you need to do is subclass `ProductFactory` and change the values in `private static $classMapping`. – deceze Oct 26 '12 at 13:29
  • Yeah, that makes sense and I agree.I suppose the problem you are trying to solve would dictate how you needed to do things. As you mentioned, "If there is no problem coupling Foo to A" – frosty Oct 26 '12 at 13:36
  • Oh, decoupling and using the abstraction further is a good point. And honestly, I am one of the guys who like to use this pattern if it is reasonable. But I have not seen the advantages of it. Thanks. – Christian Waltjen Oct 26 '12 at 13:50
1

It depends.

Design patterns are there to solve a problem, not to create a problem.

  • If you would create products inside another class the factory could provide a mock object for testing.
  • If you would create products with different kind of data to the constructor, a factory would come in handy.
  • If you would strict use dependency injection, you do not need a factory
  • If there is no real reason for a factory, do not use one.
JvdBerg
  • 21,777
  • 8
  • 38
  • 55