2012-02-06 113 views
5

我对DDD(域驱动设计)在过去几天感兴趣,但我无法弄清谁创建和验证实体的责任。我会打破这个问题以涵盖不同的场景。DDD - 实体创建和验证责任

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

  2. 集合实体。让我们假设我们有一个Post实体和评论实体。我想获得所有评论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。

回答

4
  • 工厂应该只有关心创建实体。我个人更喜欢在我的视图和模型层中进行验证。我会使用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分钟内获得百万次点击,那么最好使用延迟加载来避免在需要时提取不需要的数据。但是如果你的数据库比较小,你可以完美地使用急切的加载而不牺牲太多的性能。 同样,这是个人喜好的问题。

希望一些这种散漫有道理,欢呼!

+0

感谢您的评论! A)我不确定是否要在实体中进行验证。你会考虑验证captcha是否是业务逻辑的一部分?如果我有管理面板手动添加用户而不需要验证码? B)是的我可以,但问题是这是谁的责任?验证图层?厂?库? C)好吧,但是如果我的用户有帖子发表评论,如果加载所有这些数据以显示用户个人资料页面,这会很聪明吗? – 2012-02-08 21:35:32

+1

a)它确实取决于您的需求,我发现使用助手类在实体本身进行验证“更容易”。但增加一层额外的验证非常好。 b)我会说这是验证层的责任。如果两个账户不能有相同的号码,并且您尝试添加一个已经存在的号码,这意味着该实体** ** **,或者至少这就是我的想法。 – jere 2012-02-09 18:02:13

+1

c)这也取决于你想要什么。如果您要在个人资料页面上一次显示所有信息,那么请在一次调用中加载所有信息。但是如果你展示的是,只能发布帖子,并且当你点击一个显示评论的时候,最好在那一刻加载评论,或许使用ajax – jere 2012-02-09 18:03:14

1

最好的和最简单的方法是使用Doctrine2。也许第一个小时很难,但是一旦你掌握了Doctrine2,所有这些关系和聚合都是小菜一碟。

您可以在http://giorgiosironi.blogspot.com/或只是通过Google搜索找到关于PHP & DDD或Doctrine2的大量信息。

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

这里有很多关于这些主题的其他帖子 - 尝试使用上述关键字。

+0

当时我使用了教条,并不是很喜欢它,它很大很重。然而,它是在学说2之前,我可能会再次给主义一个镜头。不过,我仍然对正确的做事方式感兴趣,而不是寻找现成的解决方案。至于验证,感谢您携带SRP!我完全忘了它,并不确定是否应该插入另一层验证,现在我确定我需要:) – 2012-02-08 21:31:29

+0

Doctrine基于Active Record模式,Doctrine2正是您需要的,以便于实现DDD。正如我在另一篇类似的文章中所写的那样 - 自制解决方案通常最终会因为维护恶梦和聚合根源变得非常手动。通常每个AR都是根据开发人员制作的不同方式完成的。在那里,相信我,你不想这样... – 2012-02-14 02:24:25

+0

我有“重新发明轮子”综合征。如果我被要求在时间紧迫的情况下在我的工作场所实施DDD,我可能会遵循Doctrine。由于我的问题是从我的个人项目中提出的,我没有严格的死线,所以我更愿意通过实​​施这些东西来尽可能多地学习。我有一个很好的ATM解决方案,但恐怕只要病人尝试复杂化它就会中断,所以我正在考虑教义。此外,AFAIK Doctrine不支持非数据库存储(即基于文件的数据库或noSQL数据库),这可能是未来的问题(我确定编写驱动程序不是问题)。 – 2012-02-14 08:16:13