【问题标题】:Service / repository design in DDDDDD 中的服务/存储库设计
【发布时间】:2018-09-15 19:00:33
【问题描述】:

我目前正在学习 DDD,出于测试目的,我正在开发一个简单的博客系统,但我不知道如何正确设计我的服务和存储库。

我有:

  • 发布实体
  • 发表评论实体
  • 发布标签实体

我有一个页面,我想在其中显示一个特定帖子的所有 cmets 和标签。

我从以下控制器操作开始:

function showPost($postId) {
    try {
        $postEntity = $this->postService->find($postId);
    } catch {PostNotFoundException $e) {
        // ...
    }

    $postComments = $this->postCommentService->findAll($postEntity);
    $postTags     = $this->postTagService->findAll($postEntity);

    // return to view...  
}

在互联网上的大多数示例中,我读到直接使用控制器(应用层)中的实体不是一个好主意,实体应该只在域服务中使用。所以我试着把它们移到那里:

function showPost($postId) {
    $postComments = $this->postCommentService->findAll($postId);
    $postTags     = $this->postTagService->findAll($postId);

    // return to view...  
}

但是现在我的服务中有重复的代码,我必须在两个服务中注入 PostRepository:

// in postCommentService
function findAll($postId) {
    try {
        $postEntity = $this->postRepository->find($postId);
    } catch (PostNotFoundException $e) {
        // ...
    }
    $postComments = $this->postCommentRepository->findAll($postEntity);
    return $postComments; // convert to DTO before return
}

// in postTagService
function findAll($postId) {
    try {
        $postEntity = $this->postRepository->find($postId);
    } catch (PostNotFoundException $e) {
        // ...
    }
    $postTags = $this->postTagRepository->findAll($postEntity);
    return $postTags; // convert to DTO before return
}

第三个问题是我的视图中还需要 postEntity(或它的 DTO 等效项),因此控制器中会有另一个(第三个)查询。

是否有针对我的问题的通用解决方案?根据 id (postId) 及其“子对象”(cmets 和标签)查询对象(post)?

或者在控制器中查询一个实体,直接用它来查询服务可以吗?

【问题讨论】:

标签: php domain-driven-design repository-pattern


【解决方案1】:

我的问题有通用解决方案吗?

没有魔法。

您可能应该考虑“查看服务”;将 postId 作为参数,并返回一个 DTO,其中包含构建视图所需的内容。

视图服务又需要三个方法

  • postId -> 帖子
  • postId -> 列表(cmets)
  • postId -> 列表(标签)

关键的想法是,一旦你有了帖子、cmets 列表和标签列表,你实际上并不关心它们来自哪里。这就是存储库的重点——它hides the decision 关于如何从不关心的代码部分中持久化数据。

try {
    $postEntity = $this->postRepository->find($postId);
    $postComments = $this->postCommentRepository->findAll($postId);
    $postTags = $this->postTagRepository->findAll($postId);

    return $this->createDTO($postEntity, $postComments, $postTags);
} catch (PostNotFoundException $e) {
    // ...
}

对于仅从数据模型读取的用例,一旦您拥有所需的原始数据,就无需再考虑存储库。在与存储库交互的代码和针对实体的内存表示进行工作的代码之间进行清晰的逻辑分离通常很有用。

如果您想要一个更“面向对象”的 API,您可以将构建 DTO 的工作放到 post 实体本身中

try {
    $postEntity = $this->postRepository->find($postId);
    return $postEntity->createDTO($this->postCommentRepository, $this->postTagRepository);

} catch (PostNotFoundException $e) {
    // ...
}

在这里,存储库是一种“域服务”,为 postEntity 提供构建 DTO 所需的读取能力。

【讨论】:

    猜你喜欢
    • 2013-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-03
    • 2012-09-09
    • 2011-09-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多