干净架构 - 罗伯特·马丁 - 如何连接用例

18
我正在尝试实现Robert Martin描述的清洁架构。 更具体地说,我正在使用VIPER,这是Clean Architecture的iOS版本。
我的问题如下: 用户开始查看地图上的地点(标记)。 如果他点击按钮,则会放置一个标记,并且他将被带到另一个视图以创建(或编辑,如果它是对现有标记的单击)该地点(或取消)。 在这个其他视图中,用户可以编辑地点的信息,然后单击“返回”或“完成”(或“编辑”)。 如果他点击“完成”,PlaceDetailsViewController向PlaceDetailsPresenter发送包含地点信息的消息,并且PlaceDetailsPresenter使用CreatePlaceInteractor创建地点。该互动器返回用于标识地点的GUID。
如果用户在创建地点之前单击返回,则回到地图并将删除已放置的标记(因为它没有GUID,所以是新地点并消失)。 如果他在创建后单击返回,则标记仍然存在(因为它应该有GUID)。
我该如何连接它们,并将信息(包括GUID)存储在哪里? 更明确一点: 1.谁应该通知MapPresenter针保留在那里还是离开了? 是PlaceDetailsPresenter还是应该将此信息传递给PlaceDetailsWireframe->MapWireframe->MapPresenter->MapView? 2.在返回之前,这个GUID应该存储在PlaceDetailsPresenter还是PlaceDetailsViewController中?
目前我的情况是: enter image description here 编辑: 基本上,我认为问题在于VIPER来自Robert Martin的Clean Architecture,他来自Web(Rails)背景,因此他不太关注状态(或在演讲中不指定)。
我的问题主要是,状态应该存储在哪里?不同的模块应该如何通信?应该通过线框图、数据库、交互器还是通过 Presenter 之间的通信,就像这里 https://github.com/objcio/issue-13-viper-swift 中的通信一样。请注意,保留 HTML 标记。

我刚开始接触VIPER,但是让Presenter之间互相了解感觉不太对。我更喜欢通过Wireframe/Router来实现模块之间的通信。由于我还在学习这种架构,所以很乐意接受纠正。 - bennythemink
我倾向于与您想法一致,尽管我仍未找到如何在它们之间传递信息的决定性答案,无论是更好地通过线框传递数据结构(有两个选项,在使用相同的大数据结构或沿途不断更改以仅传递必要的最小量的信息(这最终会创建更多不可重用的类)),还是在Interactors中保存状态并用它们检索另一个presenter中的信息。我发布了另一个stackoverflow问题,解释了我所说的大数据结构,但还没有找到它。 - Rodrigo Ruiz
http://stackoverflow.com/questions/29054526/viper-should-the-interactor-return-only-the-necessary-information - Rodrigo Ruiz
2个回答

29

我对于Viper不是很了解,所以无法对此发表评论。不过,系统的总体状态应由实体对象保存并由交互器进行操作。GUI的详细状态(如选择矩形等)应由控制器和展示器之间的特殊连接进行管理。

在您的情况下,有两个屏幕:地图和地点编辑器。单击地图会导致调用placePinController。它会收集点击位置和任何其他上下文数据,构造一个placePinRequest数据结构,并将其传递给PlacePinInteractor,该交互器检查针的位置,必要时进行验证,创建一个Place实体来记录针,构造一个EditPlaceReponse对象并将其传递给EditPlacePresenter,这样就可以打开地点编辑器屏幕。

如果在地点编辑器屏幕上单击“完成”按钮,则会调用EditPlaceController,将编辑后的数据收集到EditPlaceRequest数据结构中,并将其传递给EditPlaceInteractor等等。

您特别询问了针的GUID。那将由Place实体创建并传回给editPlacePresenter PlacePinInteractor。


也许我表达不够清晰,但我的意思是:点击事件发生在MapPresenter中,但地点只有在用户在PlaceDetailsViewController(类似于视图)中按下“完成”后才会创建。当用户点击“完成”时,地点被创建。如果用户点击“返回”,则应返回到MapPresenter,然后不要解除大头针(或者如果它尚未创建,则解除它)。 - Rodrigo Ruiz
所谓状态,是指在地图上暂时创建的标记(pin)之类的东西。这样当我们从PlaceDetailsViewController/Presenter返回时,就知道要关闭或保留哪个标记(并提供GUID以进行关联)。 - Rodrigo Ruiz
1
将“完成”和“返回”视为不同的用例(不同的交互者)。 - Robert Martin
“back” 交互器会做什么? - Rodrigo Ruiz
2
@RobertMartin假设点击地图会创建一个实体。你认为只有在创建过程完成后才应该创建实体。这两种解决方案都可行,但需要不同的通信渠道。如果你能够在不违反业务规则的情况下使用缺失值创建实体,则Bob的方法更容易:如果单击返回按钮取消创建,则删除实体。如果这样不行,可以使用临时DTO进行传递。(NSDictionary可能行,但我建议使用自定义值对象进行数据净化。) - ctietze
@RobertMartin:“...构造一个EditPlaceReponse对象并将其传递给EditPlacePresenter,后者会打开地点编辑器屏幕”- EditPlacePresenter如何知道在哪里显示地点编辑器屏幕?该信息(顶部视图或类似信息)位于MapController中。 - Rodrigo Ruiz

0

在纯VIPER中,路由器应该以协议的形式持有模块输入。而模块Presenter应该符合它。因此,当路由器使用其他模块的路由器来组装新模块时,它将其输入传递给它。

然后第二个路由器将输入分配给其Presenter的输出。因此,第一个模块的Presenter基本上成为第二个模块的Presenter的代表。

因此,在您的情况下,当用户选择一个地方时,MapPresenter会向MapInteractor请求GUID,并告诉MapRouter导航到该GUID的详细信息。

MapRouter要求PlaceDetailsRouter为此GUID组装PlaceDetailsModule,并将MapModuleInput传递给它。PlaceDetailsRouter将MapModuleInput分配给PlaceDetailsPresenter。PlaceDetailsRouter将GUID放入PlaceDetailsInteractor中。


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