0

當我使用面向對象設計模式時,我想確保我真的瞭解它。我瞭解依賴注入的重要性以及服務容器/工廠對象的重要性。我喜歡工廠方法的想法,它可以在通過靜態方法加載時將依賴關係注入自身,並返回完整的副本。我喜歡在消費者對象的代碼中這是多麼的乾淨。而且,在測試中,你可以注入不同的對象,而不是(覆蓋或不使用工廠方法實例,見下文)在工廠方法(PHP)中正確使用依賴注入

是否有關於以下代碼,提高了警鐘什麼?我是否正確理解這一點?

abstract class AbstractClass 
{ 
    public function __construct() 
    { 

    } 

    public static function factory() 
    { 
     throw new Exception ('Please create a concrete class version of the method ' . __FUNCTION__); 
    } 

    public function inject ($class, $className=null) 
    { 

     if ($className === null) 
     { 
      $className   = get_class ($class); 
     } 

     $this->{$className} = $class; 
    } 
} 

class ConcreteClass extends AbstractClass 
{ 
    public static function factory() 
    { 
     $me = new self; 
     $me->inject (RebarClass::factory()); 
     $me->inject (AsphaltClass::factory()); 
     $me->inject (CementClass::factory()); 

     return $me; 
    } 

    public function doSomething() 
    { 
     echo $this->RebarClass->doSomethingCool(); 
    } 

} 

class RebarClass extends AbstractClass 
{ 
    public static function factory() 
    { 
     return new self; 
    } 

    public function doSomethingCool() 
    { 
     return "I did something, but it wasn't that cool...\n"; 
    } 
} 

class AsphaltClass extends AbstractClass 
{ 
    public static function factory() 
    { 
     return new self; 
    } 
} 

class CementClass extends AbstractClass 
{ 
    public static function factory() 
    { 
     $me = new self; 
     $me->inject (AsphaltClass::factory()); 
     $me->inject (SandClass::factory()); 

     return $me; 
    } 
} 

class SandClass extends AbstractClass 
{ 
    public static function factory() 
    { 
     return new self; 
    } 
} 

對我來說,這給了我很多,當我創建和控制器等機型使用對象的靈活性,我可以像實例:

$concreteClass = ConcreteClass::factory(); 

現在我的目標設定起來的方式,我想

print_r ($concreteClass); 
echo "\n"; 

輸出:

ConcreteClass Object 
(
    [RebarClass] => RebarClass Object 
    (
    ) 

    [AsphaltClass] => AsphaltClass Object 
    (
    ) 

    [CementClass] => CementClass Object 
    (
     [AsphaltClass] => AsphaltClass Object 
     (
     ) 

     [SandClass] => SandClass Object 
     (
     ) 

    ) 

) 

和國內的其他對象很容易使用

echo $concreteClass->doSomething(); 

而且,如果你想用這個單元測試,您可以執行:

$concreteClass = ConcreteClass::factory(); 
$concreteClass->inject(new DifferentAsphaltClass, 'AsphaltClass'); // overwrite 

OR

$concreteClass = new ConcreteClass; // now you are responsible for setting up dependencies yourself 
$concreteClass->inject (new YetAnotherAsphaltClass, 'AsphaltClass'); 

回答

1

提出的方法有一些風險與正確注入所需的課程有關,如果不使用工廠。

由於所需的注射列表不可用,因此代碼也有點難以遵循。

我建議使用類構造函數作爲依賴關係的接收器而不是使用注入方法。

class Concrete { 
    public static function Factory() { 
     $rebar = Rebar::Factory(); 
     $asphalt = Asphalt::Factory(); 
     $sand = Sand::Factory(); 

     return new Concrete($rebar, $asphalt, $sand); 
    } 

    public function __construct(IRebar $rebar, IAsphalt $asphalt, ISand $sand) { 
     $this->Rebar = $rebar; 
     $this->Asphalt = $asphalt; 
     $this->Sand = $sand; 
    } 
} 

IRebar的,IAsphalt,和ISand可以是接口(http://php.net/manual/en/language.oop5.interfaces.php)。

interface IRebar { 

} 

class MyRebar implements IRebar { 
} 
+0

PHP有接口,太 – nickb

+0

我喜歡你更容易找到所需要注射的思想。但使用構造函數消除了工廠方法的目的(至少,據我瞭解)。我想要一些能夠輕鬆實例化對象的東西,並且如果稍後需要對它進行更改,則它在一個地方,而不是在整個代碼中。同時,我想留下覆蓋測試對象的可能性等。 – Hans

+0

哦!我現在馬丁。只有當我使用「新」時,構造函數纔會起作用。尼斯;任何其他的想法?否則,我開始非常喜歡這種處理它的方法。 – Hans