1

[译] Android 架构:Part 2 —— 介绍 Clean Architecture

 2 years ago
source link: http://www.androidchina.net/10037.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
[译] Android 架构:Part 2 —— 介绍 Clean Architecture – Android开发中文站
你的位置:Android开发中文站 > 热点资讯 > [译] Android 架构:Part 2 —— 介绍 Clean Architecture

在本系列的第一部分,我们介绍了我们在寻找可行架构的道路上所犯过的错误。在这部分,我们将介绍传说中的 Clean Architecture。

当你在谷歌搜索 “clean architecture” 时,你看到的第一张图片是:

1.jpg

它也被称为洋葱架构,因为图看起来象个洋葱(你会意识到你需要写样板代码写到哭);或者是端口和适配器,因为你可以看到右图的一些端口。六角架构是另一个相似的架构。

Clean Architecture 是前面提到的 Uncle Bob 的心血结晶,他是 《代码整洁之道》的作者。这种方法的要点是,业务逻辑(也称为 domain),是宇宙的核心。

掌控你的领域(domain)

当你打开项目时,你应该已经知道这个 app 是做什么的,与技术无关。其它一切都是实现细节。譬如,持久化就是一个细节。定义接口,创建一个快速的粗糙的内存内(in-memory)实现,不要想太多,直到完成业务。然后你可以决定怎样真正地持久化数据。数据库,网络,两者结合,文件系统 —— 或者仍然保留在内存中,或者结果你根本不需要持久化。总之一句话:内层包含业务逻辑,外层包含实现细节。

话说回来, Clean Architectue 有一些特性使这成为可能:

  1. 层与层之间的通信
I.依赖规则

依赖规则可以用下图解释:

2.jpg

外层应该依赖内层。那三个在红色框框内的箭头表示依赖。与其使用“依赖”,也许使用“看见”、“知道”、“了解”这类术语更好。在这些术语中,外层看见,知道,了解内层,但内层看不见,也不知道,更不了解外层。正如我们先前所说,内存包含业务逻辑,外层包含实现细节。遵循依赖规则,业务逻辑既看不到,也不知道,更不了解实现细节。这正是我们努力想要做到的。

如何实现依赖规则取决于你。你可以把它们放到不同的包,但小心“内层的”包不要使用“外层的”包。然而,如果有人不知道依赖规则,没有什么可以阻止他破坏规则。一个更好的方法是把层分离到不同的 Android 模块(modules,即子项目),并在构建文件(build.grale)中调整依赖,这样内层就无法依赖外层。

还有值得一提的是,虽然没人可以阻止你跨层依赖,譬如蓝色的层的组件使用红色的层的组件,但我强烈建议你只访问相邻的层的组件。

II.抽象

抽象原则之前已有所暗示。也就是说,当你朝图中间移动时,东西变得更抽象。 这是有道理的:正如我们所说内层包含业务逻辑,而外层包含实现细节。

3.jpg

甚至可以在多个层之间划分相同的逻辑组件,如图所示。 内层定义更抽象的部分,外层定义更具体的部分。

举个例子说清楚些。我们可以定义一个 “Notifications” 的抽象接口,并将其放到内层,这样你的业务逻辑需要时可以使用它来向用户显示通知。另一方面,我们可以这样来实现该接口,即使用 Android NotificationManager 显示通知来实现,并把该实现放到外层。

以这种方式,业务逻辑可以使用这样的功能 —— 通知(在我们的例子中)—— 但它不了解实现细节:实际的通知是如何实现的。此外,业务逻辑甚至不知道实现细节的存在。来看下面这张图片:

4.jpg

当将抽象规则和依赖规则组合在一起时,结果是使用通知的抽象业务逻辑既不会看到,也不会知道,更不会了解使用 Android NotificationManager 的具体实现。这很好,因为我们可以在业务逻辑毫不知情的情况下切换具体实现。

让我们把这种规则组合和标准的三层架构简单对比下,看看它们各自的抽象和依赖是怎样的以及如何工作的。

5.jpg

在图中,你可以看到,标准三层架构的所有依赖最终都传到数据库。也就是说,抽象和依赖(方向)并不一致。在逻辑上,业务层应该是 app 的中心,但它却不是,因为依赖朝向数据库。

业务层不应该知道数据库,应该反过来。在 Clean Architecture 中,依赖朝向业务层(内层),并且抽象也上升到业务层,因此它们很好地匹配。

这是重要的,因为抽象是理论,依赖是实践。抽象是 app 的逻辑布局,依赖关系是(组件)如何实际组合在一起。在 Clean Architecture 中,这两者是匹配(译者注:指方向一致)的。而在标准三层架构中则不然,如果你不小心,很容易导致各种逻辑上的不一致和混乱。

III.层与层之间的通信

现在我们将 app 分模块,将所有内容分开,将业务逻辑放在我们 app 的中心,并在外层实现细节,一切看起来都很棒。 但是你可能很快遇到一个有趣的问题。

如果你的 UI 是一个实现细节,网络是一个实现细节,业务逻辑在中间,那么我们如何从互联网获取数据,经过业务逻辑,然后发送到界面?

业务逻辑在中间,应该协调网络和界面,但它甚至不知道两者的存在。这是一个关于通信和数据流的问题。

我们希望数据能够从外层流向内层,反之亦然,但依赖规则不允许。 让我们举个最简单的例子。

我们只有两层,绿色和红色的。绿色的是外层,它知道红色的,红色的是内层,它只知道自己。我们希望数据从绿色流向红色,然后折回绿色。该解决方案先前已经暗示过了,看下图:

6.jpg

图的右边部分显示了数据流。数据源于 Controller,经过 UseCase(或者替换成你选择的组件)的输入端口,然后通过 UseCase 本身,最后通过 UseCase 输出端口发送到 Presenter。

图的主要部分(左边)的箭头表示组合和继承 —— 组合用实心箭头表示,继承用空心箭头表示。组合也被称作 has-a 关系,继承被称作 is-a 关系。圆圈中的 “I” 和 “O” 表示输入和输出端口。可以看到,定义在绿色层中的 Controller,拥有一个(has-a)定义在红色层中的输入端口。UseCase(齿轮,业务逻辑,现在不重要)是一个(is-a)(或实现)输入端口,并且拥有一个(has-a)输出端口。最后,定义在绿色层中的 Presenter 实际上是一个(is-a)定义在红色层的输出端口。

现在,我们可以将其与数据流匹配。Controller 拥有一个输入端口 —— 拥有一个指向它的引用。它调用输入端口的一个方法,这样数据就从 Controller 流到输入端口。但输入端口是一个接口,而它的实际实现是 UseCase。也就是说,它调用 UseCase 的一个方法,这样数据就流向了 UseCase。UseCase 执行某些操作,并希望将数据发送回来。它拥有输出端口的一个引用 —— 输出端口定义在同一层 —— 因此它可以调用上面的方法。因此,数据流向输出端口。最后 Presenter 是,或者实现了输出端口,这是魔法的一部分。因为它实现了输出端口,数据实际上流到它那了。

巧妙的是,UseCase 只知道它的输出端口,世界在此停止(意指数据流到此结束)。

Presenter 实现了它(输出端口),实际上它可以被任何对象实现,因为 UseCase 不知道或不关心这些,它只清楚其层内的一亩三分地。可以看到,通过结合组合和继承,我们可以使数据流向两个方向,尽管内层并不知道它们在和外部世界通信。瞄一眼下图:

7.jpg

可以看到,和依赖箭头一样,has-a 和 is-a 箭头也指向中间。这是符合逻辑的。根据依赖规则,这是唯一可行的方法。外层可以看到内层,但不能反过来。唯一复杂的部分是,is-a 关系尽管指向了中间,却反转了数据流。

请注意,定义输入和输出端口是内层自己的职责,因此外层可以使用它们与其建立通信。我说过,这个解决方案先前已经暗示过,而且已经有了。那个讲解抽象的通知例子,也是这种通信的一个例子。我们在内层定义了一个通知接口,业务逻辑可以用来向用户显示通知,但是我们在外层也定义一个实现。在这种情况下,通知接口是业务逻辑的输出端口,用来和外部世界(在本例中,就是和具体的实现)通信。你不需要把你的类命名为 FooOutputPort 或者 BarInputPort,我们命名端口只是为了解释理论。

那么,它是过度复杂,过度费解的过度工程吗?好吧,当你习惯了,它就简单。并且这是必要的。它允许我们使得好的抽象/依赖实际匹配真实世界的通信和工作。也许这一切都提醒你不过是空中楼阁:美丽,理论上优雅,但过于复杂,我们仍然不知它是否有效,但在我们的案例中,它确实有效。

这就是本系列的第二部分。最后,第三部分,毕竟我们已经了解了理论和架构,将讲解所有你需要了解的那些图上的标签。换句话说,分离的组件。我们将向你展示一个真实的应用于 Android 的 Clean Architecture。

转载请注明:Android开发中文站 » [译] Android 架构:Part 2 —— 介绍 Clean Architecture


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK