Android Clean architecture Controller可以访问ViewModel

Android Clean architecture Controller可以访问ViewModel,android,ios,flutter,clean-architecture,Android,Ios,Flutter,Clean Architecture,根据这张图片,我有一个问题 控制器不应该访问Presenter或ViewModel,但是,如何通过单击更新视图,即用户单击增加ViewModel中计数器的按钮(因为这是保存视图状态的类),然后相应地更新视图。 但是,如果控制器可以访问演示者,我可以绕过用例直接调用演示者,然后这个类相应地更新ViewModel。 我已经阅读了很多文章和方法来做到这一点,并将控制器与演示者混合在一起。在我看来,我将打破单一的责任,因为控制器不仅负责创建输入数据,还负责添加逻辑并呼叫演示者。 如何使用图片中的体系结构

根据这张图片,我有一个问题

控制器不应该访问Presenter或ViewModel,但是,如何通过单击更新视图,即用户单击增加ViewModel中计数器的按钮(因为这是保存视图状态的类),然后相应地更新视图。 但是,如果控制器可以访问演示者,我可以绕过用例直接调用演示者,然后这个类相应地更新ViewModel。 我已经阅读了很多文章和方法来做到这一点,并将控制器与演示者混合在一起。在我看来,我将打破单一的责任,因为控制器不仅负责创建输入数据,还负责添加逻辑并呼叫演示者。
如何使用图片中的体系结构来实现这一点?ViewModel的目的是以便于UI的形式保存数据

如果用户界面需要的是点击次数——应该是这样,但如果我理解正确,您希望的是使该数据有状态,例如,将其保存到数据库中,并在每次需要增加数据时提取数据

从这个角度来看,您应该为您的数据库(存储库)定义一个接口,当然还要加上一个适当的实现(可能是一个重数据库,也可能只是一个文本文件)


最后,演示者只应将最新值(由输出数据调节)投影到ViewModel中。

您应该偏离特定原则/架构的时刻,是遵循它比不遵循它更不方便的时刻。这是因为无论我们谈论的是软件还是实际的建筑,项目需求都会塑造架构。一开始,尝试让架构在每种情况下都能工作是可以的,但这主要是为了让您可以在它不适合给定情况时学习

不幸的是,我并不完全了解这张照片的来历,但从你提到的SRP来看,它看起来要么是Bob叔叔的作品,要么是灵感来源。我认为您可能犯了与我和其他数千名开发人员在SRP方面犯的相同的错误。引用清洁建筑(Bob叔叔的书):

在所有坚实的原则中,单一责任原则 (SRP)可能是最难理解的。这很可能是因为它有 一个特别不合适的名字。这对程序员来说太容易了 听到这个名字,然后假设它意味着一个模块应该 有一件事

对于上下文,单词module并不意味着Gradle module,Bob叔叔继续将单词定义为表示源文件的意思(在OO中,我们可以认为类似于控制器的类)。我将留给你们去研究Bob叔叔对SRP的真正含义,因为我不再使用这个术语,也不想解释它。这些都不是对鲍勃叔叔的不尊重;我很喜欢他的工作

回到这个问题,我很难在不了解更多关于控制器的上下文的情况下回答(它是否只是处理点击并将其转发给适当的交互者?)。我假设这是一个Android应用程序,在这种情况下,我只需将Controller和Presenter合并到一个类中。在我看来,这既不违反Bob叔叔的SRP(即分离因不同原因而改变的事物),也不会导致类的内聚性低(这涉及模块/类/函数/源的功能)。我意识到这部分是主观的,但在我看来,处理UI交互和为ViewModel准备返回的后端数据都符合特定GUI功能的表示逻辑的角色

如果做不到这一点,请忽略我所说的以及图表所告诉您的内容,只需查看代码即可。把它们分开比分开真的能解决更多的问题吗?据此行动

考虑到您提到的要求,我看不出任何合理的方法可以完全遵循此图,但如果我真的必须将控制器和演示者分开,我会做以下几点: 在控制器和演示者(或者可能是演示者和交互者)之间使用观测者(发布者-订阅者)模式…这不是我要做的,但此图也没有反映我通常如何使用交互者)。您可以使所有内容保持松散耦合,避免在它们之间出现具体的引用(即绘制箭头)

您可以有一个用例,它的唯一目的是处理鼠标单击并向演示者返回它发生的情况。老实说,这似乎是一个荒谬的解决方案。拥有一个封装UI中递增计数器的业务逻辑的交互器有什么意义?除非您每次都保存该计数器,否则术语“业务逻辑”一开始似乎并不合适


希望这有帮助;我只是想分享一下我过去的经验,以防有所帮助。

我想问的是,例如,我们不需要从数据库中获取任何东西,也不需要在后端或某些逻辑中执行任何操作,控制器是否可以直接调用演示者?从技术上讲,任何事情都是可能的,包括控制器调用演示者。但这违反了您要求遵循的图像中表达的架构。那么,如果我不需要用例,正确的方法是什么呢?基本上,当您没有用例时,您就没有架构,所以只需让控制器创建ViewModel,仅此而已。