【问题标题】:Clean Architecture - Injection of app services into another app services清洁架构 - 将应用服务注入另一个应用服务
【发布时间】:2021-02-22 08:20:49
【问题描述】:

我正在使用 PHP API 尝试遵循清洁架构模式,以便将来能够将应用程序的模块提取到微服务中。

我的问题是应用程序服务应该如何在不耦合的情况下相互使用。 即使我正在注入绑定的抽象(接口),注入服务的方法也在处理主机服务域之外的实体。所以将来我会耦合服务,我将无法将它们外部化。

<?php

/* Domain: INJECTED */
class InjectedService implements InjectedServiceInterface 
{
    public function get(int $id): InjectedServiceDomainEntity 
    {
        return $this->repo->findById($id);
    }
}

/* Domain: HOST */
class HostService implements HostServiceInterface 
{
    /** @var InjectedServiceInterface $injectedService */
    private $injectedService;

    public function __construct(InjectedServiceInterface $injectedService)
    {
        $this->injectedService = $injectedService;
    }

    public function someMethod($someId)
    {
        /** @var InjectedServiceDomainEntity $injectedServiceEntity */
        $injectedServiceEntity = $this->injectedService->get($someId);
        // here I'm managing an outsider entity
    }
}

someMethod 我没有耦合服务吗?管理来自另一个服务/域的实体? 当我想将HostService 移动到微服务时会发生什么?

非常感谢您的想法。

【问题讨论】:

  • 你确定这2个服务是应用服务吗?您提供的注入服务的代码可以是域服务,或者如果您只需要获取实体,您可以只注入 repo
  • @MohamedBouallegue 是的,分别是 OrderServicePaymentService。一个需要另一个。问题更像是这是 DTO 的地方,或者这些只是在层之间传递数据

标签: dependency-injection domain-driven-design clean-architecture decoupling coupling


【解决方案1】:

即使您使用的是 PHP,以下内容可能在概念层面上也很有用

可能最简单的方法是实现一些您在应用程序层中依赖的通用调解器(集成问题)。

我有一个简单的开源 implementation,另一个选项是 Jimmy Bogard 的 mediatr

在我的实现中,特定参与者将依赖于相关服务并根据传递的相关消息采取行动。任何给定的参与者都可以响应各种消息。在您的情况下,可能有两个参与者,每个参与者都依赖相关服务。

这种机制在尝试减少注入到类或由类使用的依赖项数量时也很有效。

过去我也使用过一个应用程序Task(不要与.Net Task 混淆)代表一个用例,然后它会接受both OrderService 作为以及PaymentService(在此处使用您的示例)并以相关方式与两者进行交互。一个对另一个的代码依赖可以被提取成有意义的方法。

中介是这个概念的一个更隐含的实现,而某些用例特定的类会更明确。

【讨论】:

    【解决方案2】:

    如果我能正确理解您的问题,有两个服务,例如 OrderServicePaymentServiceOrderService 需要 PaymentService

    有两种情况

    第一种情况: PaymentServiceOrderService的第三方,可以独立开发。如果是真的,最好把PaymentService放到Infrastructure层,注入到OrderService这样的应用层服务中。

    第二种情况: PaymentService 不是第三方。 就干净代码而言,这种情况下存在问题。单一责任原则将被违反。更改 someMethod 等方法的原因不止一个。从另一个服务内部的另一个服务调用一个方法会产生不止一个改变的理由。最好在表示层调用PaymentService 并获取OrderService 所需的数据,然后可以通过传递数据调用OrderService 中的someMethod 而无需注入PaymentService

    讨论这类问题有点困难。希望能正确地说出我的意思。 ;)

    【讨论】:

      【解决方案3】:

      如果服务 X 使用服务 Y,您将始终存在耦合,但是:

      清洁架构及其依赖倒置原则为您提供了使耦合或依赖单向的必要工具。

      在您的情况下,DI 和接口允许您让 Host 模块依赖于 Injected 模块,但绝不会反过来。如果将InjectedServiceInterfaceInjectedServiceDomainEntity 的接口移动到主机模块中,您甚至可以使主机模块不依赖任何东西。如果您现在调用get,您将只处理来自主机模块的源代码。

      使用 DI,这些接口在不同的模块中实现。对于微服务,这些接口由远程调用基础架构组件实现。

      试图将耦合减少到零是没有意义的,因为那样你的模块根本不会交互。至少在源代码中是这样的

      再想一想:在像 PHP 这样的动态类型语言中,如果你愿意的话,你可能确实有机会通过使用函数类型而不是声明的接口作为参数和实体/对象的鸭子类型来实现更多的解耦。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-10-14
        • 2013-12-22
        • 1970-01-01
        • 1970-01-01
        • 2014-01-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多