0

我有一个 PHP MVC 应用程序,我的“M”有一个服务层、映射器层和域层。我应该在哪里以及如何检查以确保对象具有所有必需的属性?

在我看来,这些职责不属于映射器或服务层,因此离开了领域层本身。checkRequired()我在我的基础域类中放置了一个方法。它根据属性数组检查对象的属性$_required,如果缺少任何属性,则会引发错误。

从数据库中检索对象时,我一直在调用checkRequired()对象构造函数中的最后一个命令。如果对象是新实体(即未从数据库中检索),我提供一些默认值(在构造函数中),然后调用checkRequired().

虽然这一直工作正常,但我现在开始在我的(有点贫血的)域对象上放置一些行为方法,但我遇到了麻烦。例如,一个用户可以拥有许多宠物,所以在我的用户模型上我放了一个addPet()方法。我知道我需要传入 Pet 对象,因为最好注入依赖项,因此我真正的方法签名是User::addPet(ConcretePet).

但这就是问题所在!如果没有用户(作为它们的所有者),我的宠物就无法存在,所以我无法实例化ConcretePet!我可以让宠物上的用户可选,但这将是一个倒退。我可以移动checkRequired()其他地方的内容,但在哪里?

解决这种常见问题的典型方法是什么?

4

3 回答 3

1

那 checkRequired 不是 DDD 方式。一个实体应该一直有效。换句话说 - 您不应该有办法将其置于无效状态(如缺少属性)。如何?当您只拥有自己设置的公共属性时,这很乏味。您保留在数据库中的属性应该是私有的。设置它们的唯一方法是通过具有业务意义的方法。这些方法应该检查所有的不变量(不仅仅是必需的字段——所有类型的使实体有效或无效的约束)并在其中一些不满足时阻止更新。

关于 User->Pet 主题:如果 Pet 没有 User 就无法存在,那么 User 可能是一个 Aggregate Root,负责保护与 User 和 Pets 相关的不变量。这意味着应该有一个方法 addPet ......好吧......也许更有意义?采用宠物和品种宠物(它们的规则和输入可能略有不同)?而这个adoptPet应该确保宠物拥有一个用户的不变性......顺便说一句 - 为什么是用户而不是所有者?

但 Pet 也可以是聚合根。这意味着它的构造函数应该需要一个用户参数。

请注意,这取决于用例什么是聚合根。在某些情况下,宠物被视为聚合根,但在宠物采用的情况下,它是用户聚合的一部分。

于 2013-08-07T11:32:56.723 回答
0

尽可能建立无方向的关系。如果可以单独跟踪宠物(我的意思是没有用户),请将其视为聚合根。

在宠物中放置一个用户属性,但在用户中没有宠物属性。因此,您不需要在 User 中使用 addPet() 方法。

如果要查找属于某个用户的所有宠物,请改用查询:

public class PetRepository {
    public List<Pet> findByOwner(String uid) {
        //omitted codes
    }
}

希望这可以帮助。

于 2013-07-13T04:49:29.290 回答
0

从数据库中检索对象时,我一直在调用 checkRequired() 作为对象构造函数中的最后一个命令。

离题,但这可能是有问题的。假设一组必需的属性在某个时候发生了变化,使得持久化的实体不再有效。您仍然希望能够重构它们,因此您不应该在重构时运行该检查。相反,仅在创建时或行为期间运行验证。

关于addPet方法,不是传递具体宠物类的实例,而是传递创建宠物实例所需的数据作为方法参数或作为 PetInfo 类的实例。这将允许User该类创建一个完全有效的Pet.

于 2013-07-15T18:01:34.643 回答