从@tereško的answer学习如何构建模型时,我找不到服务之间通信的最佳方式。我还发现this答案,这与我正在处理的情况类似,但这个例子很适合展示。因此,从这个意义上说,当服务只能访问域和映射器工厂对象时,如何在Blog服务中检索识别服务。我是否从控制器发送它?或者我是否也需要发送服务工厂?
更新: 我没有提供一个例子,因为我提到tereško的第二个答案与我想要达到的非常相似。我正在尝试构建一个BlogService,例如存储帖子。为了存储帖子的作者,我试图检索(他的被叫)识别服务以获得登录用户(显然是帖子的作者)。
class BlogService
{
public function storePost($title, $content)
{
$post = $this->domainFactory->build('Post');
$mapper = $this->mapperFactory->build('Post');
$post->setTitle($title);
$post->setContent($content);
$post->setAuthor( /* get logged in user */ );
$mapper->save($post);
}
}
答案 0 :(得分:11)
所以基本上你的问题是“如何使用某些内容服务从识别服务共享域对象?”。实际上我已经考虑了一段时间了。
我认为,这里有4种选择。两个糟糕,一个好,一个在中间:
之前提到“通过服务工厂”的方法。
这是最天真的解决方案,因为在现实世界中,对象图最终会出现无法控制的增长 - 包含服务的服务包含服务.. ad nauseum 。
这是不可持续的,但很快。
以这种方式改变识别服务,它将Account
实例反射回控制器,然后控制器又传递给其他服务。
基本上,您最终会在层之间创建故意泄漏,以最大限度地降低复杂性。你可以称之为“架构非规范化”。
这是一个黑客和糟糕的架构。
使用DI容器在服务之间共享域对象(甚至是映射器)。
这种方式在前两个方面比较精细,但它也可以让你完全摆脱服务中的工厂。
最佳选择,但需要其他技能和代码。
使用您的域对象工厂仅创建一次Account
(以及所有其他或所选的实例)的实例。
有点像this帖子,但对于域对象。当然,您还需要一些方法来绕过“缓存”,因为一大组域对象需要多次启动才能启动。因此 - 需要一些配置。
一个棘手的中途解决方案,但允许您在服务中保留熟悉的API。
我自己目前正在使用选项2.原因是我没有可以使用的DI容器(我只在5分钟前想到了“选项4”)。您在“PHP DI容器”描述中看到的大部分内容实际上是各种服务定位器(在这种情况下,无论如何您最好使用一堆工厂)。
如果您想使用DI容器,我的认可是Auryn。
我之所以不使用它是因为我真的很傲慢,我想制作自己的DI容器。
而不是写这个:
$post->setAuthor($user);
你应该写这样的东西:
$post->setAuthorId($user->getId());
..有两个原因:
Post
实例来管理它与其他实体的关系。这就是你的服务。Account
实例,那么无论如何都会最终提取ID。所以你违反Law of Demeter没有任何实际好处。答案 1 :(得分:1)
我的猜测是domainFactory和mapperFactory是Abstract Factory模式的实例。
由于您的BlogService已经需要这两个抽象工厂,为什么不拥有第三个ServiceFactory。
此对象的责任是创建(最好是抽象)产品,服务。