服务如何相互通信?

时间:2014-12-15 21:18:18

标签: php model-view-controller soa

从@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);
    }
}

2 个答案:

答案 0 :(得分:11)

理论

所以基本上你的问题是“如何使用某些内容服务从识别服务共享域对象?”。实际上我已经考虑了一段时间了。

我认为,这里有4种选择。两个糟糕,一个好,一个在中间:

  1. 之前提到“通过服务工厂”的方法。

    这是最天真的解决方案,因为在现实世界中,对象图最终会出现无法控制的增长 - 包含服务的服务包含服务.. ad nauseum

      

    这是不可持续的,但很快。

  2. 以这种方式改变识别服务,它将Account实例反射回控制器,然后控制器又传递给其他服务。

    基本上,您最终会在层之间创建故意泄漏,以最大限度地降低复杂性。你可以称之为“架构非规范化”。

      

    这是一个黑客和糟糕的架构。

  3. 使用DI容器在服务之间共享域对象(甚至是映射器)。

    这种方式在前两个方面比较精细,但它也可以让你完全摆脱服务中的工厂。

      

    最佳选择,但需要其他技能和代码。

  4. 使用您的域对象工厂仅创建一次Account(以及所有其他或所选的实例)的实例。

    有点像this帖子,但对于域对象。当然,您还需要一些方法来绕过“缓存”,因为一大组域对象需要多次启动才能启动。因此 - 需要一些配置。

      

    一个棘手的中途解决方案,但允许您在服务中保留熟悉的API。

  5. 自白

    我自己目前正在使用选项2.原因是我没有可以使用的DI容器(我只在5分钟前想到了“选项4”)。您在“PHP DI容器”描述中看到的大部分内容实际上是各种服务定位器(在这种情况下,无论如何您最好使用一堆工厂)。

    如果您想使用DI容器,我的认可是Auryn

    我之所以不使用它是因为我真的很傲慢,我想制作自己的DI容器。

    P.S。

    而不是写这个:

     $post->setAuthor($user);
    

    你应该写这样的东西:

    $post->setAuthorId($user->getId());
    

    ..有两个原因:

    • 您没有使用有效记录。因此,您无需Post实例来管理它与其他实体的关系。这就是你的服务。
    • 如果您通过了整个Account实例,那么无论如何都会最终提取ID。所以你违反Law of Demeter没有任何实际好处。

答案 1 :(得分:1)

我的猜测是domainFactory和mapperFactory是Abstract Factory模式的实例。

由于您的BlogService已经需要这两个抽象工厂,为什么不拥有第三个ServiceFactory。

此对象的责任是创建(最好是抽象)产品,服务。

http://en.wikipedia.org/wiki/Abstract_factory_pattern