DDD-实体创建和验证责任


DDD - Entity creation and validation responsibility

最近几天我对DDD(域驱动设计)很感兴趣,但我不知道谁创建和验证实体的责任。我将打破这些问题,以涵盖不同的场景。

  1. 规则实体(可能带有值对象)。作为一个例子,让我们以一个通过电子邮件识别的用户为例。我有一个UserFactory,它接收一个数据数组(可能来自表单POST),并向我返回一个新的UserEntity。工厂是否应该验证数据的完整性(例如:电子邮件中的字符串是真实的电子邮件,密码字段1和字段2中的密码匹配等)?工厂是否应该验证是否已经不存在这样的用户(我们不想用同一封电子邮件注册两个用户)?如果是,它应该自己做还是使用UserRepository?

  2. 聚合实体。假设我们有一个Post实体和Comments实体。我想得到12号帖子的所有评论,所以我做了一些类似的事情

    $post=$postRepository->getById(12);

应该如何实现getById?像这样:

public function getById($id) {
    $postData = $this->magicFetchFromDB($id);
    $comments = (new CommentRepository())->getForPost(12);
    return new PostEntity($postData, $comments);
}

或者可能是负责懒惰创建评论的帖子,比如:

class PostEntity {
    public function getComments() {
        if(is_null($this->_comments)) $this->_comments = (new CommentRepository())->getForPost($this->_id);
        return $this->_comments;
    }
}

我在这里很失落,而且没有足够的关于PHP中DDD示例的信息,所以任何帮助都将不胜感激!

非常感谢,skwee。

  • 工厂应该只关心创建实体。我个人更喜欢在我的视图和模型层中进行验证。我会使用一些库,比如jQuery的验证插件,在客户端进行一些重要的验证(比如检查所需字段是否有数据)。然后对模型进行"核心"验证。我通过使用一个简单的BaseEntity抽象类来实现这一点,所有实体都对该抽象类进行了扩展,由于您要求提供一个示例,因此它是:

    abstract class BaseEntity {
        public function isValid();
    }         
    class MyEntity extends BaseEntity {
         public function isValid() {
             //actual validation goes here
         }
     }
    

    您还可以使用带有一些基本验证方法的静态助手类:

    class ValidationHelper {
        public static function isValidPhonenumber($value) {
            //check valid phonenumber, using a regex maybe
        }
        public static function isAlphanumeric($value) {
            //check for letters and numbers only
        }
    }
    

    许多人反对静态方法,因为它们会破坏单元测试,但在这种情况下,它们非常基本,没有外部依赖关系,因此使它们"更安全"。

  • 当涉及到检查已经存在的实体时,您可以通过在添加/更新之前查询数据库来查看实体是否已经存在,或者(我喜欢这样做)您可以向数据库中不能重复的列添加unique索引,然后将创建或更新查询包装在try-catch块中(例如,如果两个用户有相同的电子邮件,则查询将抛出唯一的约束冲突),然后显示正确的错误消息

  • 关于你的最后一个问题,它归结为一个偏好问题。如果您的数据库在1分钟内获得一百万次点击,那么最好使用延迟加载来避免在需要之前获取不必要的数据。但是,如果您的数据库相对较小,则可以在不牺牲太多性能的情况下完美地使用热切加载。同样,这是个人偏好的问题。

希望这些漫无边际的话能讲得通,干杯!

实现这一点的最佳和最简单的方法是使用Doctrine2。也许最初的几个小时会很艰难,但一旦你掌握了教义2,所有这些关系和总和都是小菜一碟。

你可以找到大量关于PHP的信息;DDD或Doctrine2http://giorgiosironi.blogspot.com/或者只是通过谷歌搜索。

回复:验证-考虑到单一责任原则,我们使用验证对象。验证可能很复杂,可能需要其他存储库或实体,因此最好将其与验证的实际实体分开,以避免创建臃肿的对象。您可以使用访问者或规范设计模式。

这里还有很多关于这些主题的其他帖子——试着使用上面的关键词。