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

2023-11-06 17:58

本文主要是介绍洋葱架构简介——分离是为了更好的结合,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

洋葱架构,也成为整洁架构(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.chinasem.cn/article/358151

相关文章

Spring Security简介、使用与最佳实践

《SpringSecurity简介、使用与最佳实践》SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,本文给大家介绍SpringSec... 目录一、如何理解 Spring Security?—— 核心思想二、如何在 Java 项目中使用?——

Spring 中的切面与事务结合使用完整示例

《Spring中的切面与事务结合使用完整示例》本文给大家介绍Spring中的切面与事务结合使用完整示例,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录 一、前置知识:Spring AOP 与 事务的关系 事务本质上就是一个“切面”二、核心组件三、完

ShardingProxy读写分离之原理、配置与实践过程

《ShardingProxy读写分离之原理、配置与实践过程》ShardingProxy是ApacheShardingSphere的数据库中间件,通过三层架构实现读写分离,解决高并发场景下数据库性能瓶... 目录一、ShardingProxy技术定位与读写分离核心价值1.1 技术定位1.2 读写分离核心价值二

Java Stream 并行流简介、使用与注意事项小结

《JavaStream并行流简介、使用与注意事项小结》Java8并行流基于StreamAPI,利用多核CPU提升计算密集型任务效率,但需注意线程安全、顺序不确定及线程池管理,可通过自定义线程池与C... 目录1. 并行流简介​特点:​2. 并行流的简单使用​示例:并行流的基本使用​3. 配合自定义线程池​示

PostgreSQL简介及实战应用

《PostgreSQL简介及实战应用》PostgreSQL是一种功能强大的开源关系型数据库管理系统,以其稳定性、高性能、扩展性和复杂查询能力在众多项目中得到广泛应用,本文将从基础概念讲起,逐步深入到高... 目录前言1. PostgreSQL基础1.1 PostgreSQL简介1.2 基础语法1.3 数据库

Spring Security 前后端分离场景下的会话并发管理

《SpringSecurity前后端分离场景下的会话并发管理》本文介绍了在前后端分离架构下实现SpringSecurity会话并发管理的问题,传统Web开发中只需简单配置sessionManage... 目录背景分析传统 web 开发中的 sessionManagement 入口ConcurrentSess

Python库 Django 的简介、安装、用法入门教程

《Python库Django的简介、安装、用法入门教程》Django是Python最流行的Web框架之一,它帮助开发者快速、高效地构建功能强大的Web应用程序,接下来我们将从简介、安装到用法详解,... 目录一、Django 简介 二、Django 的安装教程 1. 创建虚拟环境2. 安装Django三、创

MySQL中读写分离方案对比分析与选型建议

《MySQL中读写分离方案对比分析与选型建议》MySQL读写分离是提升数据库可用性和性能的常见手段,本文将围绕现实生产环境中常见的几种读写分离模式进行系统对比,希望对大家有所帮助... 目录一、问题背景介绍二、多种解决方案对比2.1 原生mysql主从复制2.2 Proxy层中间件:ProxySQL2.3

SpringBoot结合Knife4j进行API分组授权管理配置详解

《SpringBoot结合Knife4j进行API分组授权管理配置详解》在现代的微服务架构中,API文档和授权管理是不可或缺的一部分,本文将介绍如何在SpringBoot应用中集成Knife4j,并进... 目录环境准备配置 Swagger配置 Swagger OpenAPI自定义 Swagger UI 底

MySQL 索引简介及常见的索引类型有哪些

《MySQL索引简介及常见的索引类型有哪些》MySQL索引是加速数据检索的特殊结构,用于存储列值与位置信息,常见的索引类型包括:主键索引、唯一索引、普通索引、复合索引、全文索引和空间索引等,本文介绍... 目录什么是 mysql 的索引?常见的索引类型有哪些?总结性回答详细解释1. MySQL 索引的概念2