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?
the abstract factory pattern,the static factory method, the simple factory (also called factory).
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.
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.
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".
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:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With