混淆的术语:Clean Architecture中的交互器

25

根据干净架构,设计 Interactor 是包含所有业务逻辑的部分。Interactor 这个术语对我来说相当令人困惑。Interactor 对我来说好像是在数据和呈现器这两个不同的层之间进行交互。

它是使用正确的术语吗? 请问有人可以详细解释 Interactor 的目的吗? 它遵循哪种模式? 如果 Interactor 不是我所认为的那样,则用于层之间交互的设计模式是什么?


用例:这些用例编排了数据流向实体的过程。也被称为交互器。http://fernandocejas.com/2014/09/03/architecting-android-the-clean-way/ - tiny sunlight
Interactore有两个职责,管理数据流和执行业务逻辑? - Vijay Vankhede
我不知道。我认为你应该读一下示例。 - tiny sunlight
6个回答

23
Interactor 是一种与“业务逻辑”概念无关的设计模式。不深入详细介绍 Interactor 模式,它是 Command pattern 的扩展;每个“业务逻辑”对象都被视为“黑盒子”,只是要给客户端执行简单指令,将调用操作的对象与知道如何执行操作的对象解耦。(请参考文献以获得更详细的说明)。
在 Android 环境中,有一个简单的“规则”要求程序员在后台线程中执行时间长的任务,因此 Interactor 模式通过添加线程层来扩展“命令模式”。所有这些复杂的东西都是为了创建一个“清晰的架构”,其中包括可扩展、可维护和(可以说)易于理解的代码。
至于问题... 什么是层间交互的设计模式?这可能有不止一个正确答案,具体取决于情况。您可以使用简单的接口作为入口点,因此您可以使用适配器模式,或者 Facade 模式,或者如果您想做一些更高级的事情,可以实现事件总线系统。

来源: 简明设计模式解释 - 作者亚历山大·谢韦茨。第14页(适配器),第32页(命令),第47页(外观)


1
我的点赞,但请编辑并附上示例或链接。谢谢。 - trocchietto
"添加一层线程控制",只有当您的应用程序涉及线程管理时,才应在交互器中管理线程。或者作为一种捷径,当您清楚地意识到自己正在违反“干净架构”但出于方便而这样做时。 - deej

7
在清洁架构中,用例交互器是表达特定业务规则的一层。用例交互器与实体(不可知的业务规则)进行交互,以实现用例意图。实体可以在其他应用程序中使用,因为它们是不可知的;而用例交互器是特定的应用对象。
可在罗伯特·C·马丁的《Clean Architecture》第20章中找到。

6
如果你熟悉领域驱动设计,那么Interactor可以与应用程序服务进行比较。另外,说“按照清洁架构的要求,设计Interactor是包含所有业务逻辑的部分”是不正确的。相反,实体将包含业务(与应用程序无关)逻辑;而Interactor将包含特定于应用程序的逻辑。Interactor将调用实体来满足用例,其中用例可能类似于创建采购订单。
回到使用干净架构术语的话题,Robert Martin(叔叔Bob)在他的培训视频Architecture, Use Cases, and High Level Design中说了以下内容:
交互器是应用程序特定的。这意味着任何特定于应用程序的业务规则都应该在交互器内部。交互器通过调用实体内部的应用程序不可知逻辑来实现其目标的应用程序特定逻辑。例如,CreateOrderInteractor调用OrderEntity的构造函数和GetId方法。显然,这两种方法都是应用程序不可知的。正是交互器知道如何调用这两种方法以实现用例的目标。
关于您观察到的“交互器似乎像是在数据层和表示层之间进行交互”,这个工作实际上属于边界。边界位于传递机制和交互器之间,其中传递机制可能是桌面应用程序、MVC应用程序、API等。这使得实际的应用程序和业务代码与传递机制分离,并且可以从一个传递机制转移到另一个传递机制。
他还在附加部分中有一个漂亮的图表展示了交互,如果您购买视频的话。它看起来像以下内容:
传递机制== > 边界== > 交互器== > 实体
P.S. 上面提到的视频非常有趣和信息丰富。

1
根据我所读的,它相当于模型视图表现者(MVP)架构中的Presenter。它处理业务逻辑,而不是存储或显示数据。它创建了一个独立的层,与数据存储或显示的方式或位置无关。它只关心任何格式的输入和输出。它可以与观察者、适配器和外观模式结合使用,作为回调的接口、代码的通用扩展点和任何非UI或数据存储使用的解耦入口。我认为它被称为交互器是因为视图与其交互以计算值并刷新任何显示的UI元素,并且它与模型对象交互以提取数据。它也可以与数据库进行CRUD操作,但我认为这在存储库模式中已经得到了解决,因为那不是真正的业务逻辑。

好的,看起来视图调用执行并注册自己以进行回调。 - Vijay Vankhede
你可以在任何有长时间运行操作的情况下使用回调函数,但你也可以像这样使用 interactor.computeValue(input) - OneCricketeer

1
Interactors提供了各种用例的实现。理想情况下,每个用例应该有一个互动器,但根据您的应用程序规模可能会有所不同。
现在,为什么对于每个应用程序都没有意义呢?想象一下您有两个应用程序。在第一个应用程序中,您只需要读取一个用户。在另一个应用程序中,您只更新完全相同的用户。您将拥有两个不同的互动器,如GetUserInteractor和UpdateUserInteractor。如果您考虑一下,UpdateUserInteractor对于第一个应用程序(反之亦然)没有任何意义,对吧?但是您的业务/域逻辑对于两个应用程序仍然可以是相同的,其中两个服务(读取和更新)的实现例如包含在相关的业务/域对象中(或作为单独的用例对象)。这些对象显然封装了与应用程序无关的业务规则,因为它们可以插入两个或多个不同的应用程序中。
应用程序与用户之间的通信通常是特定于应用程序的。正如其他人已经提到的,您可以让互动器在用户操作上执行命令。或者您可以选择另一种类似的方式。但是,命令模式确实很方便,并且可以使整个代码更加一致、统一和易于理解。
最后但并非不重要的是,互动器的另一个重要方面是“边界接口”,这些类在输入和输出交付方面都可以进行多态部署。
(注:例如,在Android中,使用新的架构组件,Fragment / Activity 可以被视为实现输入边界,因为它将输入事件传递到业务逻辑(或领域模型) - 它是控制器。LiveData 更像是输出边界实现,因为它在底层使用观察者模式,并通过互动器将数据返回到UI。在这种情况下,我认为 ViewModel 是成为互动器的一个强有力的候选者,因为它接收输入事件(以及相应事件对应的命令),并且还包含要观察的 LiveData 实例。这些解耦是否良好,或者是否进行了多态部署?嗯,这主要与您的设计相关。而且,使用协程,现在似乎没有必要使用回调/监听器 - 因此,这个图像又增加了另一个维度。)
这是我的看法。希望它很清楚。

-3

这是MVP模式。正如您所说,它是介于Presenter和Data之间的中介(以Rest调用、共享首选项或Sqlite的形式)。


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