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