2012-10-19 138 views
1

考慮下面的代碼:爲擴展類實現工廠方法的最佳方式是什麼?

class Vehicle { 

    /** 
    * Create a new instance of Vehicle 
    * 
    * @return Vehicle 
    */ 
    public static function create(){ 

     return eval("return new " . get_called_class() . '();'); 
     // return self(); would always return Vehicle reg ardless 

    } 


    public function drive(){ 

     echo "I am a Vehicle!"; 

    } 

} 

class Bus extends Vehicle { 

    public function drive(){ 

     parent::drive(); 

     echo "\nSpecifically, a bus!"; 

    } 

} 


class Car extends Vehicle { 

    public function drive(){ 

     parent::drive(); 

     echo "\nSpecifically, a car!"; 

    } 

} 

// Drive a car 
    Car::create()->drive(); 

// Drive a bus 
    Bus::create()->drive(); 

我實現了在Vehicle類工廠「創造」的方法,讓我得到我想要使用這個類的一個實例。

我試過使用「return new self();」但總是返回Vehicle的一個實例,所以我使用了eval。

問題:是否有實現create()方法,使非EVAL方式:

  • 返回你使用
  • 它不需要類的實例在每個擴展類上實現create()
+0

是否有東西阻止你製作Factory抽象,並將'create'方法傳遞給一個表示要實例化的具體類的字符串? 'VehicleFactory :: create(「bus」);'寫的時間稍長一點,但有一點更清晰的好處。 –

+0

我只是遵循我的系統中的其他類的約定,它允許像Bus :: create() - > setSpeed(10) - > drive();我認爲這很容易閱讀,並且不需要創建工廠類。它適用於非擴展類。 – SuitedSloth

+0

儘管如此,您仍應該可以鏈接工廠,因爲它會返回一個對象。如果你對'eval()'感到不安,那麼反思可能會起作用。 –

回答

4

使用static而不是self,例如

<?php 
class Vehicle { 
    public static function create(){ 
     return new static(); 
    } 

    public function drive(){ 
     echo "I am a Vehicle!"; 
    } 
} 

class Bus extends Vehicle { 
    public function drive(){ 
     parent::drive(); 
     echo "\nSpecifically, a bus!"; 

    } 
} 

$b = Bus::create(); 
$b->drive(); 

打印

I am a Vehicle! 
Specifically, a bus! 
+0

我可以發誓我試過這個。謝謝你,先生! – SuitedSloth

1

(VolkerK打我,但是這有輕微的變化)

等待,爲什麼你需要eval()呢?不會:

public static function create() { 
    $class = get_called_class(); 

    return new $class(); 
} 

工作嗎?

+1

返回新的$ class(); :)也可以。我必須喝醉我 – SuitedSloth

+0

呵呵,我們都去過那裏。很高興你有解決方案(即使理想的不是我的)。 :) –

0

最好的方法是將工廠方法移出具體類型並轉換爲自己的工廠類。您不僅可以更輕鬆地處理這個問題,而且您還可以輕鬆地將工廠更換爲其他工廠。

我假設你知道如何繼承對象的工作,所以你不必處理任何不那麼直接的靜態,並開始站在某人的方式很快。

相關問題