【问题标题】:Put business logic in entity将业务逻辑放入实体中
【发布时间】:2013-11-29 20:48:10
【问题描述】:

我读过 Fowler 关于“贫血域模型”的文章(链接:http://www.martinfowler.com/bliki/AnemicDomainModel.html),我同意他的观点。

我尝试创建一个实体是简单 POPO 的应用程序,但这样,我有一个胖服务层,而将一些逻辑放入实体将是最简单的解决方案。

所以我会有这样的架构:

^
| Twig
| Controller | API
| Service
| Model
| Entity

地点:

实体:将是简单的 POPO,只是一袋 setter 和 getter

模型:将是用业务逻辑装饰的实体对象

服务:包含涉及多个实体的所有业务逻辑(这里我还要放置验证任务),并且充当转换器实体 -> 模型

控制器 | API:仅将 Request 与 Service、ParamConvert 匹配并检查自动化

Twig:表示层

我的问题是如何将实体层隐藏到控制器并且仅适用于模型。 为了用业务逻辑装饰我的实体,我想构建一个使用存储库并装饰结果的服务(我找不到其他方法来实现)。

所以,一个愚蠢的例子:

namespace ...\Entity\Article;
class Article {
    private $id;
    private $description;

    // getter and setter
}


namespace ...\Model\Article;
class Article {
    private $article; // all methods will be exposed in some way
    private $storeService; // all required services will be injected

    public function __construct($article, $storeService) {
       $this->article = $article;
       $this->storeService = $storeService;
    }

    public function getEntity() {
       return $this->article;
    }

    public function isAvailable() {
       return $storeService->checkAvailability($this->article);
    }

    ...
}


class ArticleService {
    private $storeService; // DI
    private $em; // DI
    private $repository; // Repository of entity class Article

    public function findById($id) {
       $article = $this->repository->findById($id);
       return new \Model\Article($article, $storeService);
    }

    public function save(\Model\Article $article) {
       $this->em->persist($article->getEntity());
    }
    ...
}

上层是按照通常的方式制作的。 我知道这不是一个好的解决方案,但我找不到更好的方法来拥有一个模型层。而且我真的不喜欢这样的东西:

$articleService->isAvailable($article);

而不是更多的面向对象:

$article->isAvailable();

【问题讨论】:

  • 我也对答案很感兴趣。为了执行他们的业务逻辑,您的模型是否具有容器意识(能够调用服务)?还是只限于他们自己?
  • 你是怎么解决这个问题的?
  • 看看GenieLamp 生成图层的软件工厂。最重要的元素是实体关系模型,可以在 1 天内编写一个 Python 生成器模块。

标签: php entity-framework symfony doctrine-orm software-design


【解决方案1】:

我有 DoctrineEntity 对象扩展 DomainModel 对象。虽然控制器实际上可能接收 DoctrineEntities,但它们仅在 DomainModelInterface 上操作。

... namespace DomainModel;
interface ArticleDomainModelInterface ...
interface ArticleDomainModelRepositoryInterface ... // create, find, save, commit
class ArticleDomainModel implements ArticleDomainModelInterface

... namespace Doctrine;
class ArticleDoctrineEntity extends ArticleDomainModel
class ArticleDoctrineRepository implements ArticleDomainModelRepositoryInterface

... namespace Memory;
// Usually dont need a memory article object
class ArticleMemoryRepository implements ArticleDomainModelRepositoryInterface

所有模型的创建和持久化都是通过存储库完成的。控制器和其他相关服务只知道 ArticleDomainModel 方法。这为您提供了很好的分离,并允许使用不同的存储库进行测试或支持不同的持久性机制。它还允许在您的域模型中使用值对象,同时仍将它们与 Doctrine 2 保持一致。

然而,在 php 中,我确实对什么样的有用业务逻辑可以实际放入域模型对象本身的概念感到困惑。我倾向于以服务中的大部分逻辑结束。那是因为我的大多数 php 应用程序都非常面向 crud。

还有一个问题:控制器本身是否应该有权访问域模型对象?

Doctrine 2 的主要开发者之一,Benjamin Eberlei,有许多关于这个主题的博客文章。他的所有文章都值得仔细阅读。以下是一些:

http://www.whitewashing.de/2013/07/24/doctrine_and_domainevents.html http://www.whitewashing.de/2012/08/22/building_an_object_model__no_setters_allowed.html http://www.whitewashing.de/2012/08/18/oop_business_applications__command_query_responsibility_seggregation.html

【讨论】:

    猜你喜欢
    • 2015-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-15
    • 2013-06-16
    • 2021-02-14
    • 2013-09-14
    • 2012-03-08
    相关资源
    最近更新 更多