gpt4 book ai didi

android - Gradle api 与多模块项目中实现的最佳实践

转载 作者:塔克拉玛干 更新时间:2023-11-02 22:50:48 27 4
gpt4 key购买 nike

这不是关于 apiimplementation 之间区别的常见问题,希望从构建多应用程序的角度来看会更先进、更有趣模块项目。

假设我在应用程序中有以下模块

  • 基础
  • feature1
  • feature2
  • 应用

现在模块之间的关系是:

base 包装library

feature1feature2 使用(依赖于)base

appfeature1feature2 放在一起

这个多模块结构中的一切都应该能够使用 Gradle 的 implementation 依赖项工作,并且不需要在任何地方使用 api 子句。

现在,假设 feature1 需要访问包含在 library 中的 base 的实现细节。

为了使 libraryfeature1 可用,据我所知,我们有两个选择:

  1. 更改 baseapiimplementation 以将依赖性泄漏到依赖于 base 的模块

  2. library 添加为 implementationfeature1 的依赖,而 base 不会泄漏对

当然,为了问题的缘故,这个例子已经被简化了,但是你明白这会如何变成一个配置 hell ,其中有大量模块和 4 或 5 级依赖关系。

我们可以创建一个 base-feature 中间模块,它可以包装 base 并为 feature1 提供另一个抽象级别以在不泄漏的情况下使用 library,但让我们将该解决方案置于此问题的范围之外,以专注于依赖项的设置。


我在上述选项中发现的一些权衡:

选项 1) 优点

  • 较小的 build.gradle 文件,因为不需要重复 implementation 子句
  • 更快地构建脚本编辑。只需对 api 子句进行单一更改,然后查看传播到所有消费者模块的更改

选项 1) 缺点

  • 类可能出现在本不应访问它们的模块中。
  • 容易被开发人员错过使用,因为他们有可用的实现,而不仅仅是模块接口(interface)。

选项 2) 优点

  • 它清楚地表明模块具有哪些依赖项。
  • 无需猜测类的来源(考虑 4 或 5 级模块泄漏依赖项),因为它们的来源始终在模块依赖项中声明。

选项 2) 缺点

  • 使更新依赖更加乏味,因为必须修改所有带有 implementation 子句的模块。尽管我认为这是一件好事,因为它可以准确跟踪变更对项目的影响,但我知道这会花费更多时间。

现在问题:

  • 在这个多模块场景的编译方面是否有任何权衡?

  • 模块泄漏依赖项是否“更快”以供消费者模块编译?

  • 它会显着缩短构建时间吗?

  • 我还遗漏了哪些其他副作用、优点/缺点?

感谢您的宝贵时间。

最佳答案

转自Gradle forum线程。

您描述的是关于分层架构系统的相当普遍的讨论,也称为“严格”与“松散”分层,或“开放”与“封闭”层。请参阅 Software Architecture Patterns 中的这一章(希望对您也免费)对于一些不太可能帮助你做出选择的符号学

从我的角度来看,如果一个模块需要打破分层,我会为项目结构建模,以最直接和可见的方式公开它。在这种情况下,这意味着添加 library 作为 feature1 的实现依赖项。是的,它使图表更丑陋,是的,它迫使您在升级时接触更多文件,这就是重点 - 您的设计存在缺陷,现在可以看到。

如果很少有模块需要以相同的方式打破层封装,我可能会考虑添加一个单独的基础模块来公开该功能,名称如 base-xyz。添加一个新模块是一件大事,不是因为技术工作,而是因为我们的大脑一次只能处理这么多“东西”(分块)。我相信当 Gradle“变体”可用时,这同样适用于它们,但我还不能断言,因为我还没有亲自尝试过它们。

如果 base 模块的所有客户端都需要访问 library(即因为您在公共(public)签名中使用了来自 library 的类或异常)那么你应该将 library 公开为 base 的 API 依赖项。缺点是 library 成为 base 的公共(public) API 的一部分,它可能比您想要的要大,并且不受您的控制。公共(public) API 是您负责的东西,您希望它保持小巧、有文档记录和向后兼容。

在这一点上,您可能正在考虑拼图模块(好)、osgi(错误...不要),或者包装您需要在自己的类中公开的部分库(也许?)

仅仅为了打破依赖而包装并不总是一个好主意。一方面,它增加了您维护和(希望)记录的代码量。如果你开始在 base 层做一些小的改编,而 library 是一个众所周知的库,你就会引入(增值)不一致——人们需要时刻警惕是否他们对 lib 的假设仍然成立。最后,瘦包装器通常最终会泄露库设计,因此即使它们包装了 API - 这仍然会迫使您在替换/升级 lib 时接触客户端代码,此时您最好直接使用 lib。

因此,如您所见,这是关于权衡取舍和可用性的问题。 CPU 不关心你的模块边界在哪里,所有开发人员都是不同的 - 有些人可以更好地处理大量简单的事情,有些人可以更好地处理少量高度抽象的概念。

当任何好的设计都可行时,不要执着于最好的设计(如 Bob 叔叔会做什么)。为了引入秩序而证明的额外复杂性是一个模糊的数量,并且是你负责决定的。让你最好的电话,不要害怕明天改变它:-)

关于android - Gradle api 与多模块项目中实现的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54554251/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com