这个问题可能是 Clean Architecture 中最具争议的问题之一,并且(据我所知)是 Hexagonal Architecture 和 Clean Architecture 差异最大的问题。
Clean Architecture 中的一般概念是:内层提供由外层实现的接口。适配器层也可以遵循这种方法。
想象一下,您想要实现一个访问 SQL 数据库的存储库模式。然后,在适配器层中,您将从用例层实现一个对用例最方便的接口。此接口可能具有特定于用例需求的 API,例如“GetAllCustomersWithOpenOrders”或“GetOrderHistoryOfCustomer”。现在为了实现这些 API,适配器需要访问 SQL 数据库为此,它会再次定义一个方便适配器的接口,因此它可能会定义通用 CRUD API 以将一些 SQL 作为字符串传递。然后,该接口将由一个类在“框架和驱动程序”层中实现,然后该类将知道如何访问数据库(它将具有连接字符串,并且可能取决于供应商特定的数据库访问库)。
使用这种方法,清洁架构的依赖规则得以维护,但它可能会引发 2 个问题:
-
如果构建 SQL 字符串,适配器是否仍然“依赖于技术”?是的,但适配器不一定需要独立于技术,如果它独立于特定框架、供应商或外部服务。我们可以很容易地添加另一个适配器,它在用例层中定义的接口和文档数据库之间“创建一座桥梁”。
-
如果我们在框架层还需要一个接口和一个实现,那么这样一个适配器的价值是什么?答案可能在很大程度上取决于这两个接口之间的“概念差异”。在上面的示例中,适配器仍将包含有关 DB 模式、如何进行连接以及如何构建复杂查询的所有知识。框架层中的实现将非常小,因为它可能只是通过供应商特定的库将 SQL 查询传递给适当的数据库实例。在对您的应用程序影响最小的情况下,可以用另一个数据库供应商替换数据库供应商。在其他情况下,配给可能相反,适配器可能只是一个“数据转换”层。
就我个人而言,我仍然没有找到解决这个问题的“灵丹妙药”,所以我尝试逐案做出“务实”的决定,正如我试图在我的博客文章中总结的那样:http://www.plainionist.net/Implementing-Clean-Architecture-Frameworks/