0

我目前正在为一个新的 Zend Framework 2 项目使用 DDD(域驱动设计)。一切正常,但我对应用程序服务有疑问。

我知道应用程序服务位于应用程序层,是领域逻辑的入口点。例如,他们可以访问域服务或存储库。

我现在想知道将应用程序服务实现为控制器插件是否有意义。在经典的 MVC 应用程序中,此控制器插件可以处理来自被调用的域服务或存储库的结果。根据这些结果,他们可以生成重定向响应或将数据/表单传递给 ViewModel。如果此逻辑封装在插件中,我的控制器只需调用插件并返回插件的结果。

我完全错了吗?或者您更愿意保留如何对控制器中的域服务或存储库的结果做出反应的逻辑?

此致,

拉尔夫

4

2 回答 2

2

当然,这有点主观,人们对这样的事情有强烈的看法……所以这是我的:

  1. 控制器插件包含对任何 MVC/REST 操作通用的代码,并且业务逻辑不是通用的。插件应该促进请求/响应的“控制”,而不是模型级别的业务逻辑。将它链接到那里会降低它的可重用性,例如用于控制台操作。此外,它还降低了将业务逻辑与其他框架一起使用的可能性。
  2. 测试很尴尬。将控制器插件作为控制器类构造函数参数注入有点多余,因为它们已经可以从注入到 AbstractActionControlleror的插件管理器中获得AbstractRestfulController。没有以明显/可见的方式(如槽构造器方法)注入依赖项使得更难弄清楚控制器类实际上依赖于什么。此外,由于所有插件(AbstractPlugin相关)都依赖于控制器实例,因此将上下文从 http 切换到控制台(如 phpunit 测试)可能会出现问题。此外,作为控制器插件编写/提供的测试逻辑迟早会升级为在测试中包含请求/响应对象,这是不必要的复杂性。
  3. 这不直观。当我听到插件时,我想到了一些小事。不是埋在如此不起眼的名字下的成熟的业务逻辑代码。因此,当我几乎没有时间调试某人的代码时,我最不需要的东西就是这样不合适。

我想再次重申,这只是我的观点。我了解到,在一个足够奇怪的用例下,很多模式都会崩溃,但到目前为止,上述几点对我和我的团队来说是有意义的。

于 2015-03-02T18:46:00.873 回答
0

作为我的解决方案的示例,您可以看到一个控制器操作:

    public function showAction()
    {
        $service = $this->readProductEntityCommand;
        $service->setId($this->params()->fromRoute('id'));

        try {
            $result = $service->execute();
        } catch (ProductException $e) {
            $this->flashMessenger()->addMessage($e->getMessage());

            return $this->redirect()->toRoute('part3/product');
        }

        return new ViewModel(
            array(
                'productEntity' => $result->getData(),
            )
        );
    }

这是一个作为命令对象构建的应用程序服务示例

class ReadProductEntityCommand implements CommandInterface
{
    protected $productRepository;

    protected $id;

    public function __construct(ProductRepositoryInterface $productRepository)
    {
        $this->productRepository = $productRepository;
    }

    public function setId($id)
    {
        $this->id = $id;
    }

    public function execute()
    {
        if (is_null($this->id)) {
            throw new ProductIdInvalidException(
                'Produkt ID wurde nicht angegeben.'
            );
        }

        try {
            $product = $this->productRepository->getProduct(
                new ProductIdCriterion(
                    new ProductId($this->id)
                )
            );
        } catch (\Exception $e) {
            throw new ProductNotFoundException(
                'Es konnten kein Produkt gelesen werden.'
            );
        }

        if ($product === false) {
            throw new ProductNotFoundException('Produkt wurde nicht gefunden.');
        }

        $result = new Result();
        $result->setValid(true);
        $result->setData($product);
        $result->setMessage('Produkt wurde gelesen.');

        return $result;
    }
}

也许这对将来的某人有帮助。

于 2015-03-04T12:51:07.247 回答