域对象工厂是什么样的?

iba*_*ore 3 php oop domain-driven-design factories

我有一个DataMapperFactory,我认为我做得正确,有一个但我有一个DomainObjectFactory但是它似乎毫无意义.就是这个:

namespace libs\factories;
use models as Models;

class DomainObjectFactory {

    public function build($name) {

        $className = 'Models\\' . $name;

        return new className();

    }

}
Run Code Online (Sandbox Code Playgroud)

我能看到的唯一优势是我保持new运算符不会出现在我的代码中.

还有DomainObjectFactory比这更多的权利吗?

任何帮助都会非常感谢.

ter*_*ško 6

使用工厂有很多主要原因:

1.摘要对象的创建

在单元测试方面,这是架构中最有用的结构之一.让工厂负责创建实例会使测试时更容易引入模拟.

此外,作为额外的好处,您不再与您使用的类的名称紧密耦合.

2.简化实例化

在这里,您必须考虑两个方面.首先 - 基于某些条件实例化不同对象的能力 - 在helmbert的答案中 已经很好地描述了(对他来说是+1).

另一种情况是当您实例化域对象时,这更复杂.像这样的东西:

$employees = new EmployeeCollection;
$address = new Location;
$class = $type . `Company`;
$company = new $class( $employee, $address );
Run Code Online (Sandbox Code Playgroud)

在创建实例之前,还有很多工作要做HoldingCompany.但这整个过程可以在工厂完成.特别是如果您的域对象工厂充分利用正确实现的DIC(这是非常罕见的,顺便说一句).

3.在对象在应用程序中释放之前准备对象

永远不应该在构造函数中进行任何计算.这使得无法测试该代码.构造函数应该只包含简单的变量赋值.

但是这引入了一个问题:有时你需要做一些逻辑操作,然后才能让其他代码结构处理你的实例化对象.作为初学者,我们通常在构造函数中执行此操作.但现在放在哪里?

这是工厂拯救的地方.

public function create( $name )
{
     $instance = new $name;
     if ( is_callable($instance, false, 'prepare') )
     {
         $instance->prepare();
     }
     return $instance;
}
Run Code Online (Sandbox Code Playgroud)

现在,当您使用时$factory->create('foobar'),您的对象已完全准备好使用.


  • 我不会.通常,您可以是简单的域对象,没有依赖项,也可以是构建复杂对象图时的情况.那时你应该使用DIC来创建/检索所述依赖项.如果创建一个特定类型的域对象更加实用,那么可能会有一些例外,但这比标准实践更为例外. (2认同)

hel*_*ert 5

通常,您可以使用工厂从特定实现中抽象出来.如果使用new <classname>运算符,则每次都实例化一个特定的类.如果您希望稍后将此类与另一个实现交换,则必须手动更改每个new语句.

工厂模式允许您从特定类中抽象.有效的最小用例可能是这样的:

interface UserInterface {
    public function getName();
}

class UserImplementationA implements UserInterface {
    private $name;
    public function getName() { return $this->name; }
}

class UserImplementationB implements UserInterface {
    public function getName() { return "Fritz"; }
}

class UserFactory {
    public function createUser() {
        if (/* some condition */) return new UserImplementationA();
        else                      return new UserImplementationB();
    }
}

$f = new UserFactory();
$u = $f->createUser();   // At this point, you don't really have to care 
                         // whether $u is an UserImplementationA or
                         // UserImplementationB, you can just treat it as
                         // an instance of UserInterface.
Run Code Online (Sandbox Code Playgroud)

当这变得非常有用时,一个用例(很多)是在进行单元测试时.在测试驱动开发中,您经常使用模拟对象(实现某个接口但实际上没有做任何事情的对象)替换类的依赖关系.使用工厂模式,使用模拟类透明地替换特定类很容易.