最近几天我对DDD(域驱动设计)很感兴趣,但我不知道谁创建和验证实体的责任。我将打破这些问题,以涵盖不同的场景。
-
规则实体(可能带有值对象)。作为一个例子,让我们以一个通过电子邮件识别的用户为例。我有一个UserFactory,它接收一个数据数组(可能来自表单POST),并向我返回一个新的UserEntity。工厂是否应该验证数据的完整性(例如:电子邮件中的字符串是真实的电子邮件,密码字段1和字段2中的密码匹配等)?工厂是否应该验证是否已经不存在这样的用户(我们不想用同一封电子邮件注册两个用户)?如果是,它应该自己做还是使用UserRepository?
-
聚合实体。假设我们有一个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/或者只是通过谷歌搜索。
回复:验证-考虑到单一责任原则,我们使用验证对象。验证可能很复杂,可能需要其他存储库或实体,因此最好将其与验证的实际实体分开,以避免创建臃肿的对象。您可以使用访问者或规范设计模式。
这里还有很多关于这些主题的其他帖子——试着使用上面的关键词。