另一个干净的架构

你在跟我开玩笑吗? 还没有足够的干净架构模式吗?

是的,有。 像VIPER / Riblets一样,它们都是完全相同的清洁体系结构原理的不同方法,但是它们在细节或处理某些元素的方法上有所不同。 一切始于著名的Bob叔叔的文章,因此请务必查看一下。 我们在这里介绍的是我们在Tooploox成功介绍的一个(感谢出色的Jorge Ortiz研讨会,不要错过他的作品)。 事实证明,这对我们的工作流程和代码质量非常有用,我们希望通过本系列文章分享一些经验。

为什么架构很重要?

在考虑我们的应用程序体系结构时,我们不应该考虑是否使用一种,而是要使用哪种。 有效的体系结构有助于创建结构化,易于理解的代码,从而降低维护成本。 由于每个人都可以独立工作,因此将所有模块模块化可以使团队合作更加轻松和富有成效。 它有助于设计解决方案并减少出错的可能性。 不必担心事物如何协同工作或如何连接某些零件,您可以专注于实际的逻辑。 最后,它将项目管理提升到一个新的水平,即由于在熟悉的环境中使用了经过验证的模板,因此计划和估算更加准确。 它还降低了新团队成员的进入门槛,并使团队更加灵活。

那么,为什么不简单地使用MVC,MVVM呢? 为什么还要另一个复杂的解决方案?

别误会,MVC和MVVM是有效的体系结构。 他们各有优缺点,可以用来创建出色的解决方案,但它们确实有局限性。 通常,MVVM很难扩展。 毕竟,移动应用几乎绝不是仅有的一些功能和几种视图。 随着功能数量的增加,MVVM开始变得难以维护,视图模型变为大规模视图模型,因此很难将所有内容按原样分开。

另外,如果您关心单元测试,那么MVC / MVP / MVVM也不是最佳选择,因为出于测试目的而分离元素和模拟依赖项要困难得多,并且每个组件往往都有多重职责。 如果您曾经使用过MVVM,则可能已经注意到它不是完整的体系结构。 它缺少诸如路由或依赖性管理之类的一些基本层,并且通常通过引入协调器或强制破坏封装并使组件以非结构化方式相互通信来完成。

通过使用干净的架构,您的代码将变得更加模块化,结构更好和高度可扩展。 每个元素都是轻量级的,并且遵循(至少尝试)遵循单一职责规则。 通过控制反转,各层具有良好的分离性,因此组件易于更换。 使用这种结构编写单元测试很简单,可以模拟依赖关系,并且功能简单且易于进行单元测试。 通过松散耦合元素,可以对同一特征进行并行编码。 只需就协议和合同达成协议,然后做好您的工作即可。 使用功能要容易得多,因为您可以一次将精力集中在一个问题上,而不必关心其他任何事情。

硬币的另一面。

但这确实有一些缺点。 它很复杂,一开始有时很难理解,而且入门门槛很高。 它也有点肿。 您将创建很多不同的协议,类,工厂,并且您将必须管理所有文件。 这不是轻而易举的事情(记住缺乏适当的反思并不能帮助迅速进行依赖注入管理)。 这些文件/类中的许多都是简单的传递实体,因此有时感觉像是在浪费时间,但这是有原因的。 它还有点违反框架和官方准则。 Apple API被设计为可与MVC配合使用,因此有时您必须要有一些技巧才能使其与干净的体系结构相处。

最终,我们发现所有的努力都是值得的,缺点并没有真正掩盖我们作为团队所获得的收益。 确实,关于干净架构的资源并不多,可以通过实际示例逐步解释一切。 我们认为这是有时在移动开发中忽略更复杂的体系结构的原因之一。 我们想改变这一点。

让我们开始吧

干净架构的主要重点是将模块分为多个层:连接器,演示者,视图,用例和网关,这些层符合SOLID原则。 使用依赖反转原理连接各层,该原理在协议之后抽象。 图层一起构成一个模块,最有可能谴责具有功能的单个视图。 这里介绍的体系结构是其非常基本的版本。 您会注意到缺少路由器组件(路由由视图或连接器处理)。

视图

您所有的UIKIt内容都归View(仅由View Controller表示)。 使其尽可能哑,避免逻辑,避免状态,仅使用简单的简单视图解释演示者传递的数据,并向演示者通知事件。

在某些情况下,尤其是在使用情节提要时,视图也会处理导航。 如果可能的话,最好将所有与平台相关的代码放在此处。 在大多数情况下,视图是整个结构的强大参考持有人。

在该连接器(在这种情况下充当路由器)呈现一个视图之后,该视图在显示时将触发演示者逻辑,仅获取所需的数据。

演示者执行用例,该用例从数据网关获取数据,对其进行处理,并在完成后传递给演示者。 一个用例可以聚合许多网关操作-例如,它可以从API调用中获取对象列表,然后获取每个对象的详细信息并返回具有完整详细信息的对象的演示者数据结构。

数据准备好后,Presenter将数据转换为可用于View的数据,例如,使用DateFormatter将日期转换为字符串,或将模型转换为可显示的数据等。然后,此类数据将传递给View。 仅通过将UI事件传递给Presenter并显示Presenter提供的内容,视图才充当被动组件。

下一步是什么

这些是Tooploox在这里使用的干净架构的最基础知识,可为您提供一些有关所有工作背后的动机的见解。 在接下来的文章中,我们将继续一些模块的实际示例,向您展示如何处理某些情况,例如路由,异步调用,无视图模块,或如何引入反应式编程。 希望你喜欢它。 我们期待您的反馈。 如果您对此有任何疑问/疑问,请写评论,我们很乐意为您提供帮助🙂