将业务逻辑放入实体中

13

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

我尝试创建一个应用程序,其中实体是简单的POPO,但这样做将导致服务层过于臃肿,而将一些逻辑放入实体中将是最简单的解决方案。

因此,我的架构应该像这样:

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

定义:

实体:是一个简单的POPO类,只包含一些setter和getter方法。

模型:是对实体对象进行业务逻辑装饰的类。

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

控制器|API:将请求与服务匹配,并执行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();

我也非常关心这个问题。为了执行业务逻辑,你的模型是否具有容器感知能力(能够调用服务)?还是仅限于自身范围内? - Thomas Piard
你是如何解决这个问题的? - vishal
请查看GenieLamp软件工厂,它可以生成层。最重要的元素是实体关系模型,可以在一天内编写一个Python生成器模块。 - serge
1个回答

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接