Php 克隆依赖项的副本(依赖项注入)有意义吗?

Php 克隆依赖项的副本(依赖项注入)有意义吗?,php,oop,dependency-injection,Php,Oop,Dependency Injection,假设我有一个类,它有几个方法,这些方法依赖于另一个对象来执行它们的任务。区别在于它们都依赖于相同的对象类,但需要不同的类实例。或者更具体地说,每个方法都需要一个干净的类实例,因为这些方法将修改依赖项的状态 这是我想到的一个简单的例子 class Dependency { public $Property; } class Something { public function doSomething() { // Do stuff $dep =

假设我有一个类,它有几个方法,这些方法依赖于另一个对象来执行它们的任务。区别在于它们都依赖于相同的对象类,但需要不同的类实例。或者更具体地说,每个方法都需要一个干净的类实例,因为这些方法将修改依赖项的状态

这是我想到的一个简单的例子

class Dependency {
    public $Property;
}


class Something {
    public function doSomething() {
        // Do stuff
        $dep = new Dependency();
        $dep->Property = 'blah';
    }

    public function doSomethingElse() {
       // Do different stuff
       $dep = new Dependency(); 
       $dep->Property = 'blah blah';
    }
}
从技术上讲,我可以做到这一点

class Something {
    public function doSomething(Dependency $dep = null) {
        $dep = $dep && is_null($dep->Property) ? $dep : new Dependency();
        $dep->Property = 'blah';
    }

    public function doSomethingElse(Dependency $dep = null) {
       $dep = $dep && is_null($dep->Property) ? $dep : new Dependency();
       $dep->Property = 'blah blah';
    }
}
这里的问题是,我必须经常检查传入的依赖对象是否处于正确的状态。新创建的状态。所以我想做点像这样的事情

class Something {
    protected $DepObj;

    public function __construct(Dependency $dep) {
        $this->DepObj = $dep && is_null($dep->Property) ? $dep : new Dependency();
    }
    public function doSomething() {
        // Do stuff
        $dep = clone $this->DepObj;
        $dep->Property = 'blah';
    }

    public function doSomethingElse() {
       // Do different stuff
       $dep = clone $this->DepObj;
       $dep->Property = 'blah blah';
    }
}
这允许我获得一个处于正确状态的对象实例,如果需要另一个实例,我可以复制它。我只是好奇这是否有意义,或者我是否过度寻找了关于依赖注入和保持代码可测试性的基本准则。

如果
doSomething()
doSomethingElse()
在两个函数中都做相似的事情,那么这是一个错误的选择。在这种情况下,它创建了一个feeder函数,并将两个不同的对象提供给该函数


但是,如果两者都负责两个需要克隆依赖对象的不同操作,那么这也不错。

DI是一种非常好的设计模式,但这并不意味着它在任何情况下都是正确的。在您的具体案例中,您说过每次都需要一个“新”副本,这意味着简单地使用“新”创建一个新实例比使用DI更有意义


DI背后的思想是松耦合——允许代码中的不同位置使用同一对象(除了它实现的接口之外,对它一无所知)——但在您的情况下,您不需要重复使用对象,因此我在这里不使用DI。

我将使用工厂模式:

class Dependency {
    public $Property;
}

class DependencyFactory
{
    public function create() { return new Dependency; }
}

class Something {
    protected $dependencies;

    public function __construct(DependencyFactory $factory) {
        $this->dependencies = $factory;
    }

    public function doSomething() {
       // Do different stuff
       $dep = $this->dependencies->create();
       $dep->Property = 'Blah';
    }

    public function doSomethingElse() {
       // Do different stuff
       $dep = $this->dependencies->create();
       $dep->Property = 'blah blah';
    }
}
通过引入一个接口,您可以进一步解耦工厂:

interface DependencyFactoryInterface
{
    public function create();
}

class DependencyFactory implements DependencyFactoryInterface
{
    // ...
}

class Something {
    public function __construct(DependencyFactoryInterface $factory) 
    ...

这是有道理的,但是,当单元测试时,我如何模拟我的依赖对象呢?你指的是模拟
Something
或模拟
Dep
?当测试某物时,我需要模拟Dep。以这种方式,无论你是否使用
Dep
DepMock
,它继承自
Dep
并覆盖任何需要的内容,但如果忽略DI,就像你说的,只是用“new Dependency()”创建一个新对象,我怎么能用一个模拟对象来交换它呢?除非我不完全理解你的意思。