The Clean Architecture

Robert C. Martin (Uncle Bob)html

原文:https://blog.cleancoder.com/u...
译:祝坤荣java

clipboard.png

在过去几年咱们看到关于系统架构的不少想法。这些包括:web

尽管这些架构在一些细节上都有不一样,它们还是类似的。他们都有一样的目标,隔离关注点。他们都经过将软件分层来达到隔离。每一个都至少有一层业务规则,另外一层做为接口。数据库

每一个这些架构产出的系统都是:安全

  1. 独立的框架。架构不依赖一些存在类库的特性。这样你能够像工具同样使用这种框架,而不须要让你的系统受到它的约束条件。
  2. 可测试。业务规则能够脱离UI,数据库,web服务器或其余外部元素进行测试。
  3. 独立的UI。UI能够很容易的更换,系统的其余部分不须要变动。例如,Web UI能够被换成控制台UI,不须要变动业务规则。
  4. 独立的数据库。你能够交换Oracle或SQL Server,用于Mongo,BigTable,CouchDB或其余的东西。你的业务规则不与数据库绑定。
  5. 独立的外部代理。实际你的业务规则并不知道关于外部世界的任何事情。

这篇文章上面的图试着将以上全部架构整合成一个可执行的想法。服务器

依赖规则

同心圆表示软件的不一样部分。大致上,你走的越远,软件的级别更高。外部的圆是机制,内部的圆是策略。微信

让这个架构工做的覆盖规则是依赖规则。这个规则说明了源代码依赖只能向内。内部圆不能知道任何外部圆的事。实践中,外部圆里一些声明的名字不能被内部圆里的代码提到。这包括,函数,类,变量或其余任何软件实体。网络

一样的,外部圆使用的数据格式不该该被内部圆使用,尤为是当这些格式是被外部圆使用的框架生成的时候。咱们不想让外部圆的东西影响到内部圆。数据结构

实体

实体封装企业域范围的业务规则。实体能够是一个有方法的对象,也能够是一组数据结构和函数。只要企业里不一样的应用可使用这些实体就能够。架构

若是你不是企业级,而只是写一个单体应用,那么这些实体就是应用的业务对象。它们封装了最通用和高层的规则。当外部变化时它们基本不太会变化。例如,你不会认为这些对象会由于页面导航或安全方面的变化而改变。任何特定应用的操做都不该该影响实体层。

用例

这层的软件包含特定应用的业务规则。它封装并实现了系统的全部用例。这些用例组织了实体中的数据流向,并指挥这些实体使用他们的企业域业务规则来完成用例的目标。

咱们不指望这层影响实体。咱们也不但愿这层会在如数据库,UI,或其余经常使用框架这样的外部变化时被影响。这层隔离了以上关注点。

固然咱们指望对于应用操做的变化会影响用例而进一步影响到这层的软件。 若是一个用例的细节变化了,那么这层的代码确定也会被影响。

接口适配器

这层的软件是一组适配器,其将数据转换成从用例和实体最合适的格式,到对于一些相似数据库或网站这种外部设施最合适的格式。在这一层,举个例子,会包含GUI的MVC架构。Presenters, Views,与Controllers都属于这里。模型基本就是从controllers传递到用例的数据结构,并从用例返回到presenters和views。

相似的,数据被转换了,在这层,从对于实体和用例合适的结构,变成对于持久层框架使用的结构。这圈内的代码不该该知道数据库。若是数据库是一个SQL数据库,那么全部SQL都应该在这层内,特别是此层与数据库有关的部分。

这层其余适配器也须要将数据从相似外部服务的外部的结构,转换成用例和实体使用的内部结构。

框架与驱动

最外层主要组合了数据库,网络框架这样的框架和工具。在这层你除了写一些与内层环通讯的胶水代码,基本不会有其余代码。

这层是全部细节存在的地方。网络是细节。数据库是细节。 咱们将这些东西放在外部保证它们不会影响其余部分。

只有四个圈?

不是的,圆圈是个示意。你可能发现你须要不止4个。没有规则说你必定要有四个。 实际上,依赖规则一直存在。源代码依赖一直指向内部。当你向内部移动时抽象的层次在增长。最外部的圆是很低层的具体细节。当你内移时软件变得更抽象,并封装了高一级的策略规则。最内部的圆是最广泛的抽象层级。

跨越边界

在图的右下方是咱们穿越圆圈边界的示例。它展现了Controller和Presenter与下一层的用例进行通讯。注意控制流。它从controller出发,穿过用例,而后在presenter里执行。也注意下源码依赖。它们每一个都指向内部的用例。

咱们一般使用依赖反转原则解决这个明显的问题。在java这样的语言中,咱们会整理源码依赖与控制流相反的接口和继承关系,让它们从边界正确的穿过。

例如,用例须要调用presenter。可是,这个调用不能直接进行由于会违反依赖规则。外圈的名字不能被内圈提到。因此咱们的用例调用内圈的一个接口(在这个例子里是Use Case Output Port),并让外圈的presenter实现它。

架构里全部的边界穿越都用这个技巧。咱们使用动态多态来建立与控制流相反的源码依赖,以便于不管在控制流的任何方向都不会违反依赖规则

什么样的数据会穿越边界

正常来讲穿过边界的数据是简单数据结构。你可使用基本结构或简单的Data Transfer 对象。或者能够方便的进行函数赋值的数据。或者你能够打包进一个hashmap,或者将它组装成一个对象。重要的是穿过边界的是隔离,简单的数据结构。咱们不想搞变通传递实体或数据库行数据。咱们不想数据结构有任何违反依赖规则的依赖。

例如,不少数据库框架在查询后返回一个方便的数据格式。咱们能够叫它RowStructure(行结构)。咱们不想将这个行机构经过边界传递给内部的圈。这会致使内部圈须要知道外部圈的内容进而违反依赖规则

因此当咱们在边界传递数据是,要注意其应该是内部圈的格式。

结论

听从这些简单规则并不难,而且能帮你减小之后的问题。经过将软件隔离分层,并听从依赖规则,你能够创建一个真正可测试的系统,包含了以上全部好处。当任何系统额外部部分过期了,好比数据库或web框架,你能够容易的替换这些过期的元素。

本文来自微信公众号「麦芽面包,id「darkjune_think」转载请注明。交流Email: zhukunrong@yeah.net

相关文章
相关标签/搜索