洋葱架构简介——分离是为了更好的结合

写出高质量软件是困难和复杂的:不仅仅是为了满足需求,还应该是健壮的,可维护的,可测试的,并且足够灵活以适应成长和变化。这就是洋葱架构出现的原因,它代表一组优秀的开发实践,用来开发任何的软件应用都是一个不错的方式。

洋葱架构,也成为整洁架构(The Clean Architecture),用来构建具有如下特点的系统:

1.    独立的Frameworks
2.    可测试
3.    独立的UI
4.    独立的数据库
5.    独立的任意外部服务(代理)

看到这张图,你应该能理解为什么称其为洋葱架构了:D, 没错,这就是它的原理图。注意,并不是只能使用4个圆环,重点在于这里的依赖原则:代码依赖是从外向内的,内环中的代码不应该知道外环中的任何东西。

这里有一些相关的词汇可以帮助更好的理解和熟悉这种方式:

  Entities:应用的业务对象。

  Use Casess: Use Casess协调(Orchestrate)数据从Entities的流入和流出,也被称为Interactors。

  Interface Adapters:这个Adapter集为Use Casess和Entities把数据转换为方便使用的格式(如渲染展示在页面上),Presenters和Controllers属于这里。

  Frameworks and Drivers:这是实现所有细节的地方:UI,Tools,Frameworks等。

 

下面用一张更生动图来辅助说明它的原理:

依赖原则(The dependency rules)

上面的同心圆代表软件的不同部分。总得来说,越往里面,代码级别越高。外层的圆是(实现)机制,而内层的圆是原则(Policies)。

让这个架构起作用的最主要原则是依赖原则。这个原则要求源码依赖只能指向内部。内部的圆不能知道外圆的任何事情。一般来说,外圆的声明(包括方法、类、变量或任何软件实体)不能被内圆引用。

同样的,外圆使用的数据格式不能被内圆使用,尤其是外圆中的Framework产生的格式。我们不想让外圆的任何东西影响内圆。

 

越往里面抽象级别越高,最外层的圆是低级别的具体细节。越往里面内容越抽象,并且封装更高级别的原则(Policies)。最里面的圆是最通用的。

Entities

Entities封装了企业级的业务规则。一个Entity可以是一个带方法的对象,也可以是一个数据结构和方法集。Entities可以被用于企业的其他应用。

如果你没有加入企业,而是仅仅在写一个简单的应用,那么这些Entities就是这个应用的业务对象。它们封装了最通用、最上层的原则。它们是最不容易改变的,即使外部的东西改变了。例如,你不想让这些对象受到页面导航、安全的影响。应用的任何操作变化都不应该影响Entities Layer。

Use Casess

这一层包含了应用特有的业务规则。它封装和实现了系统的所有用例。这些用例协调数据从entities的流入和流出,并且指导entities使用它们的企业级业务规则来达到用例的目标。

我们不希望这一层的改变影响到Entities,同时也不希望这一层被外层的改变影响,如外层的数据库,UI或者任何Frameworks的改变,这一层独立于这些关注点。

当然,我们确实期望应用的操作变化影响用例层。如果一个用例的细节改变,那么这一层的部分代码确实会受到影响。

Interface Adapters

这一层包含一个adapters set(数据适配器集),它们把适用于Use Casess和entities的数据转换为适用于外部服务(external agency,如Database或Web)的格式。 例如,这一层可以完全包括GUI的MVX架构,Presenters, Views和Controllers都属于这里。Models可能仅仅是从Controllers传到Use Casess的数据结构,然后从Use Casess返回给Presenters和Views。

 

这一层的数据会被转换,从适用于entities和Use Casess的格式转换到适用于所使用的持久化框架的格式(如数据库)。这个圆以内的代码不应该知道关于数据库的任何东西。如果是一个SQL数据库,那么所有的SQL应该被限制到这一层,并且通常来说是被限制到层中跟数据库有关的部分。

 

同样,这一层也需要一些其他必要的Adapter来把外部的数据格式(如来自于外部服务的格式),转换为适用于Use Casess和entities的格式。

 

Frameworks and Drivers.

最外面的一层通常由Frameworks和Tools组成,如Database,Web Framework等。一般来说,除了用于和内层圆交互的连接代码,你不会在这一层写很多代码。

 

这一层是实现所有细节的地方。Web和Database都是需要实现的细节。我们把这些东西放在外面以减轻来自于它们的伤害(即减轻对他们的依赖)。

 

跨界

 

在图的右下角是一个我们应该如何跨界的例子。它展示了Controllers、Presenters与下一层的Use Casess的交互。注意控制的流向,它开始于Controller,经过Use Casess,最终在Presenter中执行。同时也请注意Source Code依赖,它们每一个都指向内部的Use Casess。

 

我们通常用依赖倒置原则来解决这个明显的矛盾。比如,在Java这样的语言里,我们可以使用接口和继承关系在合适的地方让源码依赖与控制流反向来跨界。

 

例如,假设Use Cases需要访问Presenter,当然,不能是直接访问,不然会违反依赖原则,所以我们让内圆的Use Cases访问一个接口(如图中的Use Cases output port),然后外圆的Presenter实现这个接口。

在这个架构中,同样的技术也被用于跨越其他的边界。我们利用运行时多态来创建与控制流相反的SourceCode依赖以满足依赖原则,无论控制流是如何流向的。

 

通常跨界的数据都是简单的数据结构。你可以使用简单的结构或数据传输对象(Data Transfer Object)。这个数据可以简单的是方法调用的参数,你也可以把它包装到一个HashMap或者一个对象。最重要的是独立的、简单的数据结构才能跨越边界。不要投机取巧,如传输Entites或者Database rows。我们不想让这个数据结构有任何违反依赖原则的依赖。

 

例如,很多的数据库框架对于query返回一个方便的数据格式,我们可以称之为Row Structure,我们不想向内部传递这个row structure。这会让内圆知道外圆的内容而违反了依赖原则。

 

所以,我们应该以最适用于内圆使用的格式来传递跨界的数据。

 

总结

满足这些简单的原则并不难,并且会减少项目进程中很多头疼的问题。通过把软件分成几层,并且满足依赖原则,你将会创建一个本身就可测试的系统,同时还有其他的好处。当系统的任何外层部分(如Database,Web 框架)废弃的时候,你可以轻松的替换这些废弃的元素。

代码实践可以参考:https://github.com/android10/Android-CleanArchitecture/releases

本文大部分内容译自The-Clean-Architecture,其中加入了自己学习该架构时的理解,如有意见和建议,欢迎交流!

原文地址:http://www.cnblogs.com/oxgen/p/7171165.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/324651.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RBAC(基于角色的权限访问控制)

第一节.RBAC简介 英文全称(Role-Based Access Control)中文全称:基于角色的权限访问控制rbac: 一种数据库设计思想,根据设计数据库设计方案,完成项目的权限控制.经常需要添加权限的情景 4.1 不同用户登录后看到的菜单是不一样的. 4.2 不同用户看到的页面效果不一样 4.2.1 有的…

子列表只是原列表的一个视图

原文参考:《编写高质量代码:改善java程序的151个建议》本文原创:穆雄雄上期文章:subList?? subString???上期我们说到,List接口提供了subList方法,其作用是返回一个列表的子列表。并且我们通过案例说明…

python注释的用法(单and多行)

单行注释 # name"asdfdasfdas"多行注释 """ print(xy) aad2"""快捷键 先选中要注释的内容然后Ctrl/

【2018.3.17】模拟赛之二-ssl1862jzoj1366 删数【区间dp】

正题 链接 需要纪中OJ账号 有n个数,可以选择删除一段区间,价值为|xi – xk|*(k-i1)。求删完所有数的最大价值 输入输出(需要自取) Input    输入文件的第一行为一个正整数N,第二行有N个用空格隔开的N个不同的正整…

ASP.NET Core之跨平台的实时性能监控

前言 前面我们聊了一下一个应用程序 应该监控的8个关键位置. 应用程序的8个关键性能指标以及测量方法 最后卖了个小关子,是关于如何监控ASP.NET Core的. 今天我们就来讲讲如何监控它,下面上效果图: 阅读本文需要了解的相关技术与内容: InfluxDb(分布式时序数据库,开源)(注…

EasyUI(前端框架)

第一节 EasyUI的介绍和常用组件 [1]EasyUI的介绍 介绍: EasyUI是一个前端开发的框架,其将常用的页面开发使用的组件进行了 封装,前端开发人员只需将EasyUI的资源导入项目后使用即可,快速 提升开发效率。 使用: ① 导入EasyUI的资…

如何快速开发一个 Dubbo 应用

转载自 如何快速开发一个 Dubbo 应用 导读:在分布式系统中,远程调用是最基础也是最重要的基石。历史上,曾经先后出现过 CORBA、RMI、EJB、WebService 等技术和规范,在服务化以及微服务日趋流行的今天,更多的被广泛使…

‘小会计’的转行之旅

本文原创:王哈哈1大学学习的专业是会计学,目前社会上来说很普遍的工作,都说会计是越老越吃香,所以一毕业就先找了一份和专业相关的工作,然后就开始了抱着公司的大腿努力工作。毕业三年期间也换了几份工作,本…

【2018.3.17】模拟赛之三-ssl1863jzoj1367 俄罗斯方块【模拟】

正题 链接 需要纪中OJ账号 有7种方块 有n列,给出每列的方块高度,求一种方块所有方面都落地的方案数 输入输出(需要自取) Input 第一行为二个整数C和P,1 ≤ C ≤ 100, 1 ≤ P ≤ 7,表示列数和下落方…

Python缩进的几个原则

Python的缩进有以下几个原则 顶级代码必须顶行写,即如果一行代码本身不依赖于任何条件,那它必须不能进行任何缩进 同一级别的代码,缩进必须一致 官方建议缩进用4个空格

应用程序的8个关键性能指标以及测量方法

前言 高性能一直是我们作为程序员..孜孜不倦的追求.. 有的时候甚至会为了一句代码吵上几天.. 那么到底应该如何评估我们的性能指标来判断是否需要优化呢? 今天就来讲一下这个.. 说明一下,本篇是译文. 原文地址:https://stackify.com/application-performance-metrics/ …

MyBatis Plus

文章目录第一节 MyBatis Plus 的简介第二节 MyBatis Plus 的框架搭建[1] 第一步:导包[2] 搭建SSM开发环境[3] 在数据库中创建测试表[4] 在pojo层下创建Student表的实体类[5] 在mapper层创建StudentMapper接口并继承BaseMapper接口[6] 创建测试类,并从Spr…

班级日常分享,一天一瞬间

119级日常分享经过两周左右的KTV项目终于要告一段落了,上午先让各个小组在班内试讲了下自己小组所做的KTV点歌系统,整体上做的还可以,有些小组还存在一些细节问题,在试讲的时候也都给他们指了指,相信下来会有所改进的。…

DDOS 攻击的防范教程

转载自 DDOS 攻击的防范教程 一个多月前,阮一峰的个人网站遭受 DDOS 攻击,下线了50多个小时。这篇文章就是他总结的,教大家如何应对这种攻击。 需要说明的是,我对 DDOS 并不精通,从没想过自己会成为攻击目标。攻击…

【2018.3.17】模拟赛之四-ssl1864jzoj1368 燃烧木棒【最短路,Floyd】

正题 链接 需要纪中OJ账号 有n条木棒,长度为1或根号2,给出每根木棒两头的坐标,和燃烧需要的时间。只能从一个木棒的一头开始点火,求燃烧完所有木棒所需要的最短时间。 输入输出(需要自取) Input 输入…

python变量的创建过程(内存地址变化)

​ name “Alex” 原因 python 解释器有自动垃圾回收机制,自动隔一段时间把没有跟变量名关联的内存数据回收。

推荐一份基于Docker的DevOps实战培训教程

01. 基于Docker的DevOps实战培训 微软工具链 基于Azure和Team Foundation Server 微软DevOps工具链是基于Visual Studio 应用生命周期管理(VSALM - Visual Studio Application Lifecycle Managemnet)的软件管理平台,本动手实验希望通过模拟一…

所有和Java中代理有关的知识点都在这了

转载自 所有和Java中代理有关的知识点都在这了 对于每一个Java开发来说,代理这个词或多或少都会听说过。你可能听到过的有代理模式、动态代理、反向代理等。那么,到底什么是代理,这么多代理又有什么区别呢。本文就来简要分析一下。 代理技…

神奇!一行代码实现删除某集合下标20-30的元素

大家好,我是雄雄。今天我们还是分享关于集合的内容。假如有这样的需求,已知集合的长度为100,也就是集合中有100个元素,现需要删除索引20-30之间的元素,我们应该怎么实现呢?我们先初始化集合,代码…

ssl初一组周六模拟赛【2018.3.17】

前言 先说一下成绩: 姓名成绩xjq(没错又是他)310hjq200hzb150wyc(本人)130lrz130xxy100lw30zyc缺考 正题 题目1:ssl2574 & jzoj1368 无限序列【斐波那契数列】 刚开始想用分治,结果做不出来,然后想到了更好的方法&#xff…