2011-03-30 45 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