干净架构:为什么不能将实体用作用例(互动器)的请求模型?

15
我已经阅读了PPP、clean code、coder和架构书籍。
我知道:
- 清晰的架构是一种分层架构。 - 分为开放式分层架构和封闭式分层架构。 - 清晰的架构书籍建议每个层可以访问其内部层,而不仅仅是下一个内部层。
因此,我认为清晰的架构并不强制采用封闭式分层结构,它允许使用开放式分层结构。例如,在框架层中的UI可以直接访问实体(Entity),跨越两层。
我理解,如果清晰的架构强制采用封闭式分层结构,则我们不能直接从框架层实现存储库接口,而应该按照下一层的术语来实现它,这个下一层又应该按照它的下一层来实现它,以此类推。
现在我的问题是,为什么我们不能在用例或控制器层直接将实体(Entity)作为参数类型引入,而必须在中间层中定义数据结构或DTO,并费心地将实体转换为数据结构并将其作为响应返回,而我们被允许在控制器层使用和查看实体(Entity),因为访问规则没有被违反呢?
考虑以下示例,假设我们有:
- JobView - JobController - JobUseCase(RequestModel) : ResponseModel
  • JobEntity(职位实体)
  • 现在如果 JobView 想要调用 JobController,它应该传递 RequestModel。那么我们能否直接将 JobEntity 作为 RequestModel 引入,像这样:

    • JobView
    • JobController
    • JobUseCase(JobEntity)
    • JobEntity(职位实体)

    我知道这样做会增加代码的脆弱性,因为这样如果我们改变了 JobEntity,那么 JobView 也必须改变。但是干净架构是否强制要求遵循SOLID原则就像一条规则一样脆弱或刻板?!

    3个回答

    14

    为什么不能将实体作为用例的请求模型?

    你自己已经回答了这个问题:即使你没有违反依赖规则,这也会增加代码的脆弱性。

    为什么我们不能直接在用例或控制器中引入实体作为参数类型,为什么我们必须在中间层定义数据结构或DTO,并烦恼于将实体转换为数据结构并将其作为响应返回,而我们允许在控制器层中使用和查看实体,因为未违反访问规则?

    (关键业务)实体和DTO在应用程序中有非常不同的原因。实体应该包括关键业务规则,与适配器和交互器之间的通信无关。DTO应以最方便的方式实现,以增强此通信,并且没有任何直接原因依赖于业务实体。

    即使实体可能具有与DTO完全相同的代码,这应被视为巧合,因为它们更改的原因完全不同(单一职责原则)。这可能似乎与流行的DRY原则(不重复自己)冲突,但DRY表明知识不应重复,只要它们是由不同的原因更改的,代码在应用程序的不同部分仍可能看起来相同。


    11

    我不确定我理解你问题的原因:

    Clean Architecture是否强制实施SOLID原则或者作为规则而不脆弱或者僵化?

    Clean Architecture怎么可能会强制实施僵化和脆弱性?定义架构就是关于如何广泛考虑基本的面向对象编程原则,例如SOLID和其他原则...

    另一方面,你下面的例子肯定会丢失Clean Architecture的含义:

    JobView > JobController > JobUseCase(JobEntity) > JobEntity

    这暗示我们,你很可能从控制器中检索了你的实体,这完全忽略了互动器(或用例)和Clean Architecture的重点。

    互动器封装应用程序业务规则,如与实体的交互以及通过实体网关对实体进行CRUD,而实体网关则封装了基础架构层。

    此外,在“Clean Architecture”上下文中,作为模型层的一部分的实体与作为HTTP请求消息评估器的交付机制的控制器没有任何关系。以这种方式去除控制器这个较低级别的组件会对SRP(即单一职责原则)产生负面影响(导致脆弱性增加),并且会降低组件之间的解耦程度(导致刚性增加)。
    你说:
    并且我了解,如果干净架构强制使用封闭层,我们将无法直接从框架层实现存储库接口,我们应该按照下一层的术语实现它,并且这个下一层应该按照其下一层的术语实现它,依此类推。
    你的实体框架的RepositoryInterface及其实现属于基础设施层,它们应该被实体网关包装、适配。在这里,迪米特法则可能很重要,因为我们正在谈论业务模型的封闭层端口(EntityGatewayInterface)的实现。
    最后,基于上述原因,我怀疑以下假设是错误的,所有基于该假设的进一步假设也将是错误的,这会导致您完全困惑:
    所以我认为,Clean Architecture并不强制要求封闭分层,它允许开放式分层,这意味着例如在框架层中的UI可以直接访问实体,跨越了2层。
    但无论它是否强制要求封闭分层,Clean Architecture都明确而具体地定义了自己(组件之间的关系),如下面的UML类图所示:

    enter image description here

    我只能从那个图中看到一个紧密分层的架构...
    在我看来,一个开放式的层是一个矛盾之处,它不能像自然情况下的层一样限制层所应该限制的内容,因为按定义,层是一种隔离,一个组件组的抽象,被简化为其端口,旨在减少技术债务,如脆弱等...

    其他资源


    5
    以上答案是正确的,但我想指出为什么会导致混淆,因为从依赖关系的角度来看,在跨边界传递实体并没有什么问题。您不能传递任何依赖于外层的类型,因为这是明显不合适的。书中许多内容都涉及依赖性问题,所以这会引起困惑-为什么实体不可以呢?
    如上所述,实体需要像任何其他代码一样遵守SRP原则。如果您将实体用于数据传输目的,则引入了不必要的耦合。当实体由于业务原因需要更改时,至少需要更改映射代码,甚至可能还需要更改外层中的其他内容。

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