了解域对象 + 数据映射器模式?

2022-08-30 15:41:41

我过去一直使用各种ORM,并将我所有的逻辑都放在我的模型中,无论它的性质如何 - SQL,MongoDB查询甚至获取远程JSON对象。但是,当有必要确保松散耦合以实现高水平的可测试性时,这种方法的问题很快就会出现。

今天,我读到了关于将模型分成两部分的信息,& .
如果我完全理解它,就完全不知道所使用的存储,而是存在来处理业务逻辑。 另一方面负责将数据集存储在到集合数据存储中。Domain objectsData mappersDomain objectsData mappersDomain objects

然而,我确实发现很难在网上找到一个好的,易于理解的例子,说明如何在现实世界的例子中使用DomainObjects和DataMappers。

这(下面显示的代码)是在我的代码中使用DomainObjects和DataMappers来存储用户的适当方式,还是我在脑海中弄错了?

$user = new User_DO;
$userSave = new User_DM;
$userSave->store( $user->add(array('name' => 'John Doe')) );

class User_DO {

    function add($array) {
        if(!isset($array['name'])) {
            throw new Exception("Name must be set");
        }

        return $array;

    }

}

class User_DM {

    function store($array) {
        MyDatabase::execute("INSERT INTO...");
    }

}

答案 1

这背后的想法是有一个标准对象,它表示现实生活中的当前状态,换句话说,在域中。此域模型通常是没有逻辑的数据集合。

class person_DO {
    public $id;
    public $firstname;
    public $lastname;
    public $addresses;
}

此域模型(域对象)的实例的加载和持久性通过数据映射器进行处理 - 例如,上述人员的地址可能通过1:n关系位于另一个表中,如下所示:

TABLE person {
    id        INTEGER PRIMARY KEY,
    firstname VARCHAR(32),
    lastname  VARCHAR(32)
}

TABLE addresses {
    id INTEGER PRIMARY KEY,
    person_id  INTEGER FOREIGN KEY ON person.id, --Reference on person-row
    street     VARCHAR(64),
    ...
}

person_DO不需要知道这一点,但数据映射器需要知道,因为它必须在加载期间聚合数据,并在持久化期间进行分离:

class person_DM {
    /**
     * @param  [integer] $id
     * @return [person_DO] an instance of a person or null, if no person
     *                     with that id was found.
     */
    public function findById ($id) {...}

    /**
     * @return [array of person_DO]
     */
    public function fetchAll() {...}

    /**
     * persists a person object
     * @param [person_DO] an instance of a person
     */
    public function saveOrUpdate(person_DO $person) {...}
}

为了进一步分离不同的部分,DataMappers通常使用DbTable网关或类似的模式来允许使用不同的数据库或类似的操作。这样,我可以拥有多个具有相同架构的数据库,但是例如,在不同的组织中构建具有相同代码的数据仓库,只有不同的数据库对象。

作为一个实际示例,我建议查看Zend框架的快速入门教程,它完全符合我刚才简要解释的内容。


答案 2

大致的方式,是的。虽然我强烈建议不要重新发明轮子,而是使用像 Doctrine 2.x 这样的复杂 ORM 来实现这样的模式。您可以查看他们的文档(第8章:使用对象)来对界面进行采样。


推荐