Php 依赖注入和/或工厂模式

Php 依赖注入和/或工厂模式,php,design-patterns,dependency-injection,factory,Php,Design Patterns,Dependency Injection,Factory,不确定我的标题是否正确,因为我甚至不确定我使用的术语是否正确 我有一个类,它的属性是对象。设置此属性时,必须创建对象。我的问题是如何在没有紧密耦合的情况下实现这一点 例如: class A { protected $_depending; protected $_somePropertyObject; public function __construct(\Lib\Dependency $depending) { $this->_set

不确定我的标题是否正确,因为我甚至不确定我使用的术语是否正确

我有一个类,它的属性是对象。设置此属性时,必须创建对象。我的问题是如何在没有紧密耦合的情况下实现这一点

例如:

class A
{
    protected $_depending;

    protected $_somePropertyObject;

    public function __construct(\Lib\Dependency $depending)
    {
        $this->_setDepending($depending);
    }

    protected function _setDepending(\Lib\Dependency $depending)
    {
        $this->_depending = $depending;
    }

    public function setSomeProperty($someProperty)
    {
        // I want to prevent this
        $this->_somePropertyObject = new \Lib\some\Object($someProperty);
    }
}
我可以通过构造传递所需的对象,但还需要做什么

如果我正确理解工厂模式,这会发生什么变化?我仍然需要在某处创建对象?不是对象本身,而是工厂。还是紧耦合?对我来说似乎没完没了。然而,当重新分解类时,在何处以及如何生成类是孤立的

如果我将setSomeProperty函数设置为仅接受\Lib\some\Object,则仍然需要由首先传递它的父对象创建。似乎只是改变了它的创建位置

希望我对我想问的问题足够清楚

提前谢谢


编辑我要问的是创建时间、地点和原因的顺序。

当需要收集“信息”来创建存储在$\u somePropertyObject中的对象时,我喜欢使用Factory模式。例如,假设您必须为某些属性赋值以实例化它,或者在实例化之后立即运行几个方法

此外,您还需要考虑是否需要稍后更改继承树。如果您现在可能正在为$\u somePropertyObject分配一个\Lib\some\对象,您可能会发现自己希望以后可以轻松地将其交换为\Lib\some\FancyObject。如果使用依赖项注入,则可以轻松地交换子类型

这是一本入门读物:


同样:

依赖注入模式中工厂的目的是为另一个实例生成实例,而另一个实例不需要知道如何生成它

在其核心,“工厂”只是一个对象返回器:在调用时返回实例的东西

这在功能更强的语言中更容易看到。例如,在Python中,类是可调用的(没有
new
操作符),调用类会生成类的实例。因此,如果类不需要参数,则类可以是它们自己的工厂。同样,任何返回实例的零参数函数都可以被视为工厂。这使得依赖注入非常清晰,没有样板文件

在更严格的语言中(Java/C++/C#静态类型的传统,或者类或函数不像PHP那样完全是一流的),您需要在“模式”后面隐藏依赖项注入,因为。在PHP5.3+中,您可以使用闭包作为工厂,也可以按照Java/C的方式定义一个
FactoryInterface
和每个工厂一个新类

例如,对于您的类,您可以执行以下操作:

class Aprime extends A
{
    public function setSomeProperty($somePropertyFactory)
    {
        $this->_somePropertyObject = $somePropertyFactory();
    }
}
在这个类中,
setSomeProperty
需要一个可调用的零参数“工厂”,您可以这样生成:

$other_dep_factory = function(){ return new SomeOtherClass(); };
class ClassFactory {
    function __construct($classname, $args=array()) {
        $this->class = new ReflectionClass($classname);
        $this->args = $args;
    }

    function __invoke() {
        return $this->class->newInstanceArgs($this->args);
    }
}

$other_dep_factory = new ClassFactory('SomeOtherClass');
或者像这样:

$other_dep_factory = function(){ return new SomeOtherClass(); };
class ClassFactory {
    function __construct($classname, $args=array()) {
        $this->class = new ReflectionClass($classname);
        $this->args = $args;
    }

    function __invoke() {
        return $this->class->newInstanceArgs($this->args);
    }
}

$other_dep_factory = new ClassFactory('SomeOtherClass');
在PHP 5.3之前,您需要像Java那样:

interface IObjectFactory {
    function getObject();
}

// this B-and-D interface is optional
// it has no body because PHP doesn't support
// type-hinting return values
interface ISomeOtherClassFactory {}


class SomeOtherClassFactory implements ISomeOtherClassFactory {
    function getObject() {
        return new SomeOtherClass();
    }
}

class Aprime extends A
{
    public function setSomeProperty(ISomeOtherClassFactory $somePropertyFactory)
    {
        $this->_somePropertyObject = $somePropertyFactory->getObject();
    }
}


$other_dep_factory = new SomeOtherClassFactory();
$myAprimeObject->setSomeProperty($other_dep_factory);

那么你什么时候使用工厂?每当一个对象需要创建另一个对象时。如果对象只需要使用另一个对象,只需传入一个实例。

您创建的工厂在哪里以及如何创建、定义和收集信息?从第一节课开始,看到你的编辑。我还在想在哪里创建工厂对象本身?但是我在哪里创建这个工厂对象呢?我应该将其作为依赖项传递吗?最好没有静电。在创建需要它的东西之前创建它。那么它仍然紧密耦合吗?示例:公共函数something(){$factory=newfactory();}?不要说setter?在类外创建它并传入,如我上面展示的示例代码所示。每个程序都有一个地方,你可以在那里创建东西,而不是定义东西。(例如,一个
main()
方法,或者框架调用的某个方法)你可以在上面构建更多的声明性抽象,但最终你必须在某个地方说
newsomething()
!我应该为每一个班级建立一个工厂吗?工厂将能够创建对象可能需要的所有类。示例:类A获取FactoryA以创建类A所需的所有对象。在FactoryA中,它直接拥有每个类别的子工厂?例如,FactoryA可以创建配置类,也可以是数据库连接,从文件等。