2011-03-30 21 views
7

我想为我们的系统设计一组工厂类,其中工厂创建的一些对象也需要在它们可以正确使用之前被初始化。工厂类与对象初始化 - 试图避免静态

实施例:

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

对于相同的例子,让我们说,$qux对象是唯一的相依性,Foobar需求。我想获得的是:

$foobar = Foo_Factory('bar'); 

为了避免需要沿着$qux对象传递在整个系统中,并把它传递给工厂类作为另一个参数,我想执行直接在工厂类的初始化Foobar

class Foo_Factory { 

    public static function getFoo($type) { 

     // some processing here 
     $foo_name = 'Foo' . $type; 
     $foo = new $foo_name(); 
     $foo->init($qux); 

     return $foo; 
    } 

} 

有浮现在脑海中几个解决方案,但他们都不是很理想:

  1. 添加静态二传手甲基od为$qux添加到工厂类中,并让它将对$qux的引用存储在私有静态变量中。系统可以在开始时设置$qux,并且工厂类可以阻止任何未来更改(出于安全原因)。
    尽管这种方法有效,但在单元测试期间使用静态参数来存储对参考的参考是有问题的(例如,由于其静态状态,它在单个测试之间愉快地生存下来)。
  2. 使用Singleton模式创建一个新的上下文类,并让工厂类使用它来获取对$qux的引用。这可能比选项#1更清洁一些(尽管我们将静态问题从工厂类移至上下文类)。
  3. 一直使用依赖注入,即将$qux传递给使用工厂类的任何对象,并让该对象作为另一个参数传递给工厂类:Foo_Factory::getFoo($type, $qux);
  4. 与上面(#3)相同,但不是沿着系统传递$qux,而是传递工厂类的实例(即在这种情况下,它不会是静态的,而是可实例化的)。

请问您有什么建议?上述四种替代方法中的任何一种,还是有更好的方法可以做到这一点?

注:我不想在这里进入一个static is evil flamewar,只是试图想出最好的解决方案。

回答

5

我会一直使用依赖注入。但是,不要在任何地方传递$ qux,只需将其注册到依赖注入容器中,并让容器将其排除。在Symfony Component讲:

// 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'))); 
+0

啊,那是非常酷其实 - 我知道我将不得不考虑交响乐团更详细(实际)当我得到一个机会。我创建了一个简单的容器解决方案,虽然我仍然在内部使用工厂,但它的作用就像一个魅力:-)感谢您的反馈和示例! – MicE 2011-04-06 01:35:13

4

我只是做工厂方法非静态,并将它传递给需要该工厂的每一个对象。

要设置工厂,您需要在构造函数中使用参数$qux来提供工厂。

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; 
    } 
} 

有了这种方法,你应该得到的容易,你需要没有绕过服务容器或注册表的“麻烦”与工厂上班的类使用。

对于这个例子,我会用直接的方法来传递你真正需要的对象,而不是将它抽象到Container类中。

决定是否使用DIC或注册表或简单的旧DI是我认为应该为您的整个项目完成的。我强烈希望DIC优于注册表,但与正常DI相比更好。对于给定的情况,很难争取赞成或反对某种方法。

总结我的观点:如果静态工厂是问题只是使其非静态。

希望我理解您的文章权利;)

+0

谢谢edorian。最后我使用了DIC(因为实际上我比'$ qux'更有依赖性),并在整个系统中实现它。这清理了它本身,更不用说单元可测试性的改进了:-) – MicE 2011-04-06 01:31:26