从产品用例的角度获取图像和评论就像数据库访问一样。唯一的区别是您不查询数据库,而是查询另一个服务。但从产品微服务的角度来看,两者都是为您的用例提供数据的外部系统。
当您查看干净的架构时,您会意识到控制器和网关位于同一架构层 - 接口适配器。该层被称为“接口适配器”,因为它适配下层的接口。
如您所见,网关可以是数据库或外部接口(服务)。
因此,您应该以这种方式构建您的应用程序:
+------------------+
| product use case |
+------------------+
|
+------------------+---------------------+
| | |
V V V
+-----------------+ +------------------+ +-------------------+
| ImageRepository | | ReviewRepository | | ProductRepository |
+-----------------+ +------------------+ +-------------------+
^ ^ ^
| | |
===========+=====================+====================+================
| | |
+--------------------+ +--------------------+ +--------------------+
| ImageRestClient | | ReviewRestClient | | JDBCConnector |
+--------------------+ +--------------------+ +--------------------+
您可能想要选择其他命名,但结构将保持不变。
易于测试,如果您决定有一天应该在产品微服务中管理图像而不是单独的服务,您可以替换ImageRestClient
with a JDBCConnector
.
EDIT
@Rene,你能帮忙理解一下吗?我经常使用干净架构,但到目前为止我不明白为什么数据库层是干净架构中的外层。是的,这是与外部系统的通信,但是1)如果DB是一个框架,通常主应用程序会导入DB,反之亦然。
它是依赖倒置原理的应用,它告诉我们:
“高层政策不应依赖于低层细节。” - 罗伯特. C·马丁 https://cleancoders.com/episode/clean-code-episode-13
应用程序记住数据的方式是一个细节。我说“记住”,因为这是数据存储的抽象。也许数据存储在数据库中、只是文件中,甚至仅存储在 RAM 中。例如。 Web 应用程序可以使用SessionCartRepository
or a DBCartRepository
存储购物车。
我想人们有时会对干净的架构感到有点困惑,因为他们之前看到的图表将数据库放在中心。但清晰的架构图只是可视化如何构建应用程序的一种方式。
在我听说干净架构的几年前,我已经应用了它,但我的图表看起来像这样。
+--------------------+
| ApplicationService | ---+
+--------------------+ |
| | Use Case
======|===================|================
V V Domain
+------------+ +----------------+
| Repository | --> | BusinessObject |
+------------+ +----------------+
^
=======|====================================
| Database
+----------------+
| JdbcRepository |
+----------------+
好吧,2014 年我的命名有所不同。我的ApplicationService
实施的用例和我的BusinessObject
是 CA 的实体。但其结构与 CA 提议的相同。当我第一次读鲍勃叔叔的书《干净的架构》时,我认为他的图表要好得多。从那时起我也使用CA图。但有时我会使用上面显示的图表,因为有些人喜欢将数据库层出于某种原因绘制在底部。
- 当外部服务有网络模型并且用例有域模型时,哪一层应该负责从网络模型映射到域模型(通常对我来说是用例层,但这意味着内层了解外层)。外部服务层是否应该进行映射
在两种类型之间映射的组件必须知道这两种类型,因此它对这两种类型都具有依赖关系。
+------------+ +--------+ +------------+
| SourceType | <---- | Mapper | ----> | TargetType |
+------------+ +--------+ +------------+
因此,您不能将映射代码放置在实体或用例层中,因为这些层将依赖于外层,例如网络模型是详细信息。它会违反干净架构的依赖规则。
因此,您必须将映射代码放置在外层(例如网络层)。
最后编辑
您提到您的图表有点旧,因为您之前使用过它。那么目前正确的做法是什么呢?
鲍勃叔叔的方式,因为它是广泛使用的方式,并且只有他的观点被称为“清洁架构”。我的没有名字。
如果我现在理解正确的话 1)存储库应该只位于外层,并且只有用例可以与存储库对话(当然通过抽象)?
存储库实现位于外层。定义,例如接口或抽象类放置在用例层。换句话说,用例告诉了它需要什么,例如有一个接口。像数据库这样的提供者实现它。
- 领域层是干净架构中的实体? 3)或者一些Repos应该位于领域层并与DB层(外层)中的Repos对话(因此这意味着UseCases不与DB Repos对话)
这是我在听说干净架构之前的“旧”观点。我通常将存储库放在用例旁边。我通常还应用接口隔离原则,这意味着我创建特定于用例的存储库。例如。
public interface PlaceOrderRepository {
...
}
在听说 CA 之前,我将存储库定义作为抽象类放在域层中,以便可以使用 package 修饰符。这就是我今天不再做的事情。今天,我将工厂放在实体层中,可以从包范围中受益(如果我需要包范围),并让存储库使用这些工厂。
因此,我建议在用例用例层中定义用例特定存储库,并在外层(接口适配器层)中实现它们。
我想这就是为什么这一层被称为接口适配器的原因,因为它是为内圈中定义的接口实现适配器的层。