在做了两章铺垫后本章再续写第九章。我们之前介绍过了好几种架构模式,那么本章只挑一种往死了整,这个架构其实就是在DDD书中所介绍的经典四层的变更版。这里面需要注意一点,四层架构是洋葱架构的一部分,尽管洋葱型已经是微服务架构系统中一种事实上的标准,但我们不会对各类适配器做重点介绍,那些东西一般都是开源的组件或者没有业务逻辑的组件比如DAO。再说了,您都已经学习DDD了还需要我再讲解什么是DAO吗?所以我们只介绍下面图形中绿色边界内部的东西。

四层架构实际上更多的用于面向对象(也可称之为对象驱动式)编程,如果是面向过程其实经典三层就够了。下面图展示了一个典型的四层架构的构成及各层间的访问限制。如果您看过DDD相关的经典书籍会发现此图和书上的并不一致,主要原因有两点:1)省略了视图层,那个不是我们的重点;2)资源库实现理论上属于基础设施层,而我们在这里进行分开是因为这个组件比较核心,我见过较多的案例都是把资源库误当DAO用,所以需要在此重点提出来讲解。本来我这个系列文章就充满了个性,咱们直面开发中的各类痛点会提供大量的干货而不是和其它文章一样都含糊的带过去。

上图,如果将“资源库”和“基础设施”二合一,您再根据依赖关系就能推导出来这是一个典型的洋葱架构。再加上比如RESTful、MQ等适配器就是六边型架构。这回您知道为什么我说洋葱和六边型其实是一个东西的不同叫法了吧?除了层的结构信息,访问顺序也是您需要重点关注的内容,如果违反了约束所谓的洋葱也就不成立了(比如让领域模型转而依赖基础设施,那领域模型就不再是架构中的核心了)。还有一点需要说明,在一个服务中(Service)通常会包含两种不同的架构模式:查询模式架构和命令模式架构,上图属于命令模式,查询请参考下图。一般来说查询架构相对要简单的很多,使用经典三层开发模式即可。

根据上面两图所示:在同一个服务中使了两种不同的架构模式,分别为Command端(简称C端)和Query端(简称Q端)),这种方法可称之为命令查询分离(CQS,请注意与CQRS作好区分)模式,这样的区分会大大提升系统的开发效率和运行效率。由于查询操作并不会修改数据也不会包含业务逻辑,所以工程师只需要面向“系统运行性能”即可,也就是查询怎么快怎么来,层数少自然开发的速度也快,也可以把一些优化手段应用于查询相关的代码中而不用考虑事务、一致性、对象封装等各种条条框框的约束。而命令模式中,其要考虑的内容多、代码更加的严谨。不说别的,仅参数验证就够喝一壶的了(我也见过有些开发从不做参数验证,依赖于前端的正确性判定。我跟你说,别说前端了,各包之间的调用都是不可信任的,所以验证每个参数的合法性是必需甚至是强制的)……。
C端架构图中还标识了序号,表示设计的先后顺序或编写代码的顺序。由于我们使用的是洋葱架构,领域模型层必然要最先设计;紧接着自然是应用服务层,包参数验证、组织业务流程控制、存取领域模型、发布命令或事件等操作。注意,虽然此时尚没有设计数据持久化等功能,但您别忘了资源库的接口是在领域模型层定义出来的,所以是可以直接在应用服务中引用的,如果用的是Spring框架则可直接注入进来;第三个要做的工作是数据访问层的设计包括DAO和数据模型,这一层您需要根据领域模型的特性和当前系统的基础设施条件来决策使用什么样的后端存储。最后要设计的是资源库实现层,这东西负责把领域模型与数据模型互转及领域模型的事务化存储。Q端的设计顺序正好与C端相反,先设计DAO再考虑应用服务,也就是先着重查询效率再考虑数据出去前的加工。这两个设计模型的顺序限制目前并无现成的理论作支撑,应该是一种个人的最佳实践,您可以考虑在项目中实验一下,这个顺序其实也符合了上一章说的先模型后服务的建议原则。
虽然C端和Q端两个图并不是很精确,但仍然突出了厚度的不同。C端的领域模型层占比较大,Q端的应用服务层则更为厚重一点(厚重不代表要先设计,只表示其会组织查询逻辑比如数据的合并等,并非和DAO一样只单纯的关注数据的查询)。
很多DDD强调了六边形架构,但到目前为止我们在这方面并未投入过多的讲解,主要是因为时机不成熟,而有了4层架构作为基础则是最好的机会。我先贴一张《实现领域驱动设计》中关于六边型的示意图。同原图不同,我在这个图的上面画了一条橙色的竖线,作用后面说。参照咱们前面的内容相信就可以揭开这个架构的神秘面纱了。继续阅读前请您注意,这里的六边型是针对每一个限界上下文而不是整个系统。

首先,我们使用橙色的线把这个图分成了两部分,竖线左边是应用程序的输入端,右边当然就是输出了,而所有用于输入和输出的都称之为适配器。
分割后,应用程序这个小六边结构不变,是系统的核心。左边的适配器是应用程序的输入端口,如果是微服务架构自然就是RESTful、gRPC等接口层;如果是微前端就是UI层;如果需要接收MQ,自然就是消息监听组件。右边适配器是为应用服务提供输出能力,如果使用了数据库,当然就是DAO组件;如果需要发送MQ就是消息发送组件。六边型架构在现在的系统中其实非常常见,您现在系统可能就是这个架构只是不知道它名字罢了。而基于微服务架构的系统,甚至可以认为其中的每一个服务都是六边型的。讲到此处有一点需要说明:DDD书中的六边型强调了领域模型部分,而我认为这一部分是可选的,要视业务的复杂度而定。
作为六边型的核心,应用程序不能一笔带过。如果使用了对象驱动的方式,其架构自然就是上面我们所讲的四层模式;如果是事务脚本,一般无业务模型的概念,因为您的业务已经集中于应用程序服务之中了。实际上现在有很多人反对事务脚本,认为使用了事务脚本其架构就不能称之为六边型。 但我个人认为六边型是一种思想,它强调了业务应居于系统的核心,事务脚本不代表业务是分散的。此外,我们应该从业务的角度来决策架构选型而不是过份的强调技术,这个思想会贯穿本系列文章。还有一点您记住了,不论书中写的多么天花乱坠,给的永远只是参考和指导,具体哪些可以用到工作中需要进行取舍。
相信通过上面的讲解,您就会发现所谓的六边型也没什么了不起的,也搞不好会感叹一下:就这 ?
本章详细介绍了4层架构的结构、访问顺序以及设计顺序;同时,对六边型架构(也就是洋葱架构)做了补充性说明,相信您已经明白书上和网上常说的六边型是什么意思了。后面我们继续对4层架构进行深入讲解包括各类领域模型的作用以及一些代码案例。
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。问题1)我想知道rubyonrails是否有功能类似于primefaces的gem。我问的原因是如果您使用primefaces(http://www.primefaces.org/showcase-labs/ui/home.jsf),开发人员无需担心javascript或jquery的东西。据我所知,JSF是一个规范,基于规范的各种可用实现,prim
本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01 客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02 数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit
目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称
项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU
我在我的项目中有一个用户和一个管理员角色。我使用Devise创建了身份验证。在我的管理员角色中,我没有任何确认。在我的用户模型中,我有以下内容:devise:database_authenticatable,:confirmable,:recoverable,:rememberable,:trackable,:validatable,:timeoutable,:registerable#Setupaccessible(orprotected)attributesforyourmodelattr_accessible:email,:username,:prename,:surname,:
我是一名决定学习Ruby和RubyonRails的ASP.NETMVC开发人员。我已经有所了解并在RoR上创建了一个网站。在ASP.NETMVC上开发,我一直使用三层架构:数据层、业务层和UI(或表示)层。尝试在RubyonRails应用程序中使用这种方法,我发现没有关于它的信息(或者也许我只是找不到它?)。也许有人可以建议我如何在RubyonRails上创建或使用三层架构?附言我使用ruby1.9.3和RubyonRails3.2.3。 最佳答案 我建议在制作RoR应用程序时遵循RubyonRails(RoR)风格。Rails
我正在尝试创建密码规则来设计可恢复的密码更改。我通过passwords_controller.rb做了一个父类(superclass),但我需要在应用规则之前检查用户角色,但我所拥有的只是reset_password_token。 最佳答案 假设您的模型是用户:User.with_reset_password_token(your_token_here)Source 关于ruby-on-rails-设计通过reset_password_token获取用户,我们在StackOverflow
我已经使用Apartment设置了一个Rails5应用程序(1.2.0)和Devise(4.2.0)。由于某些DDNS问题,应用只能在app.myapp.com下访问(请注意子域app)。myapp.com重定向到app.myapp.com。我的用例是每个注册该应用的用户(租户)都应该通过他们的子域(例如tenant.myapp.com)访问他们的特定数据。用户不应限定在其子域内。基本上应该可以从任何子域登录。重定向到租户的正确子域由ApplicationController处理。根据Devise标准,登录页面位于app.myapp.com/users/sign_in。这就是问题开始的