Factory class with object initialization - attempt to avoid static

I am trying to create a set of factory classes for our system, where some objects created by the factory must also be initialized before they can be used properly.

Example:

$foobar = new Foobar(); $foobar->init( $qux, ... ); // $foobar ready for usage 

In the same example, we can say that the $qux object is the only dependency required by Foobar . I would like to:

 $foobar = Foo_Factory( 'bar' ); 

To avoid having to go through the $qux object throughout the system and pass it to the factory class as another parameter, I would like to initialize Foobar directly to the factory class:

 class Foo_Factory { public static function getFoo( $type ) { // some processing here $foo_name = 'Foo' . $type; $foo = new $foo_name(); $foo->init( $qux ); return $foo; } } 

There are several solutions that come to mind, but none of them are perfect:

  • Add the setter static method for $qux to the factory class and let it save the reference to $qux in a private static variable. The system can set $qux at the beginning, and the factory class can prevent any future changes (for security reasons).
    Although this approach works, using a static parameter to store a reference to $qux is problematic during unit testing (for example, it lives happily, survives between separate tests due to its static state).
  • Create a new context class using the Singleton template and let the factory class use it to get a reference to $qux . This may be a cleaner way to do this than option # 1 (although we are moving the static problem from the factory class to the context class).
  • Use dependency injection in full, i.e. pass $qux any object that uses the factory class, and let this object pass it along with the factory class as another parameter: Foo_Factory::getFoo($type, $qux); .
  • Same as above (# 3), but instead of passing $qux along the system, instead pass an instance of the factory class (i.e. in this case it will not be static, but real).

What would you recommend? Any of the four alternatives mentioned above, or is there a better way to do this, please?

Note. I don't want to get into static is evil flamewar here, just trying to find a better solution.

+7
source share
2 answers

I would go with Dependency Injection completely. But instead of skipping $ qux everywhere, just register it in the dependency injector container and let the container sort it. Symfony Component says:

 // Create DI container $container = new sfServiceContainerBuilder(); // Register Qux $container->setService('qux', $qux); // Or, to have the DI instanciate it // $container->register('qux', 'QuxClass'); // Register Foobar $container->register('foobar', 'Foobar') ->addArgument(new sfServiceReference('qux')); // Alternative method, using the current init($qux) method // Look! No factory required! $container->register('altFoobar', 'Foobar') ->addMethodCall('init', array(new sfServiceReference('qux'))); 
+5
source

I would just make Factory methods non-stationary and pass them to every object that needs this factory.

To configure Factory, you need to pass it using the $qux parameter in the constructor.

 class Foo_Factory { public function __construct($qux) { $this->qux = $qux; } public function getFoo( $type ) { // some processing here $foo_name = 'Foo' . $type; $foo = new $foo_name(); $foo->init( $this->qux ); return $foo; } } 

With this approach, you should easily use it in classes where you need to work with Factory without "problems" with passing around a service container or registry.

In this example, I would use the direct approach only to simply bypass the objects that you really need, and not abstract them in container classes.

The decision about whether to use a DIC or a registry or a plain old DI is what I think should be done for your entire project. I strongly prefer DIC in the registry, but like a normal DI, it's even better. For this context, it is difficult to argue about or against a particular approach.

To summarize: if static Factory is a problem, just make it not static.

I hope I understood your message correctly;)

+4
source

All Articles