Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP Factory methods

Tags:

I was reading up on factory methods. Can someone explain why it is suggested that factory methods be located in a separate factory class?

I am pulling my example from here: http://www.devshed.com/c/a/PHP/Design-Patterns-in-PHP-Factory-Method-and-Abstract-Factory/

class ETF {
  var $data;
  function __construct($data) {
    $this->data = $data;
  }
  function process() {}
  function getResult() {}
}

class VirtualCheck extends ETF {}
class WireTransfer extends ETF {}

class ETFFactory {
  function createETF($data) {
      switch ($data[‘etfType’]) {
      case ETF_VIRTUALCHECK : 
        return new VirtualCheck($data);
      case ETF_WIRETRANSFER :
        return new WireTransfer($data);
      default :
        return new ETF($data);
      }
  }
}

$data = $_POST;
$etf = ETFFactory::createETF($data);
$etf->process();

I would tend to instead write it like this:

class ETF {
    final public static function factory($data) {
        switch ($data[‘etfType’]) {
            case ETF_VIRTUALCHECK :
                return new VirtualCheck($data);
            case ETF_WIRETRANSFER :
                return new WireTransfer($data);
            default :
                return new ETF($data);
        }
    }

    var $data;
    function ETF($data) {
        $this->data = $data;
    }
    function process() {}
    function getResult() {}
}

class VirtualCheck extends ETF {}
class WireTransfer extends ETF {}

$data = $_POST;
$etf = ETF::factory($data);
$etf->process();

Am I wrong in doing this?

like image 373
Beachhouse Avatar asked Dec 12 '16 14:12

Beachhouse


People also ask

Which are the three types of Factory Method?

the abstract factory pattern,the static factory method, the simple factory (also called factory).

What is Factory Method?

The factory method is a creational design pattern, i.e., related to object creation. In the Factory pattern, we create objects without exposing the creation logic to the client and the client uses the same common interface to create a new type of object.

What is factory & instance methods?

A Factory Pattern or Factory Method Pattern says that just define an interface or abstract class for creating an object but let the subclasses decide which class to instantiate. In other words, subclasses are responsible to create the instance of the class.

What is Factory Method in OOP?

In object-oriented programming, a factory is an object for creating other objects; formally, it is a function or method that returns objects of a varying prototype or class from some method call, which is assumed to be "new".


1 Answers

I would not say you're "wrong", but there is a "smell". By combining the factory method in the manufactured class, the architecture violates a few of the SOLID guidelines:

  1. Single responsibility: the class now does two things (when it should do one).
  2. Open/closed principle: the class is only half open (when it should be fully open).
  3. Interface segregation: consumers of the class use the manufactured object proper methods, without the factory and vice versa (when consumers should depend only on needed methods)

I've found that the more SOLID a class is, the easier the class is to maintain in the long-term. Thus I wouldn't consider SOLID violations immediate problems, just a signal of possible trouble down the line.

So, what trouble might you run into down the line? Well, if the factory itself becomes more complex, you'll need methods to handle that additional work. These methods would not, necesasrily, be used by the class proper methods. So you'd end up with code like this:

class ETF {
    final public static factory($kind) {
        switch ($kind) {
        case 'A':
            $etf = static::factoryHelperForA();
            break;
        case 'B':
            $etf = static::factoryHelperForA();
            break;
        }
        return $etf;
    }

    public function apiMethod1() {
        $this->apiMethod1Helper();
    }

    public function apiMethod2() {
        $this->apiMethod2Helper();
    }

    // factory helper
    private static function factoryHelperForA() {
        /* lots of code */
    }

    // another factory helper
    private static function factoryHelperForB() {
        /* lots of code */
    }

    // ugh, now we have api method helpers... totally different responsibility
    private function apiMethod1Helper() {
        /* lots of code */
    }

    // still more...
    private function apiMethod2Helper() {
        /* lots of code */
    }
}

So you can see it starts to become messy as the needs of the factory grow, and as the needs of the manufactured class grow. This is what the SOLID principles are guiding you away from.

If it's important to you now to build a future flexible class, then I'd suggest busting the factory out into its own EtfFactory class.

like image 190
bishop Avatar answered Sep 24 '22 16:09

bishop