在洋葱形,六边形或干净的体系结构中,域模型可以包含与数据库中的域模型不同的属性吗?

如何解决在洋葱形,六边形或干净的体系结构中,域模型可以包含与数据库中的域模型不同的属性吗?

我问的是谁知道的并且有使用任何分层体系结构(洋葱,六角形,干净的等)构建软件的经验。每当我在Google上搜索软件体系结构时,人们都会有不同的看法并以不同的方式解释相同的体系结构。

条款

在阅读问题之前,某些术语可能会使您感到困惑,因此在下面定义它们。我不确定是否对它们有“正确的”定义,但是我从互联网上收集了这些信息。让我知道我是否误会了。

域层:包含企业/业务逻辑并使用域模型。位于中心,除域模型外,不依赖其他任何层。

应用程序层:包含应用程序逻辑,接受来自基础结构层的DTO,并传输视图模型

DTO(数据传输对象):用于在层之间进出数据的类,JSON字符串等。可能是纯数据容器。

VM(视图模型):从应用程序层传递到表示层的DTO。

DO(域模型):在域层中使用的类,JSON字符串等。可能是纯数据容器。

VO(值对象):数据库实体(数据库行)或数据库使用的数据格式。可以从数据库层转移到应用程序层。

摘要

在洋葱,六角形或干净的体系结构中,域层位于中心(即,域层不依赖于域模型以外的任何层,该域模型用于将数据传输到其他层或从更高层接受数据层)。

这意味着该域使用的域模型(DTO,POJO,VO或任何其他模型)可能与数据库用于保存持久性数据的模型不同。

我画了一个图,以便给您更好的解释。

enter image description here

enter image description here

第一季度

请查看第二张图片的红色部分。

如果域层位于中心层而不是传统的分层或n层体系结构,那么域模型是否可以具有比数据库实体(行)更多的属性(或不同的属性)?

例如,假设域层使用名为 Person 的类。用户请求在服务器中注册的所有人的图片。让我们假设数据库仅包含所有人的姓名。但是,我们可能会使用其他Web服务器通过名称请求提供人的照片。因此,应用程序层将从数据库中读取所有名称,并使用这些名称通过HTTP请求从其他Web服务器获取所有图片。之后,带有名称和图片的人物列表将作为视图模型(DTO)发送给用户。

第二季度

持久层可以由数据库,文件系统,其他Web API等组成。

表示层可以是网站,桌面应用,移动应用,Web API等。

这两个层都是基础结构层的一部分,并且取决于应用程序层,但是应用程序层仅取决于域层。

当应用程序层接受来自表示层的请求时,就没有问题,因为表示层调用了应用程序层,而表示层知道了应用程序层。

在大多数情况下,应用程序层需要从持久性层获取数据。

应用程序层无法在没有任何依赖性的情况下调用持久层,因为它不知道持久层中的任何类。

到目前为止,这就是我的理解方式,有人可以给我清楚的解释数据应该如何流动以及如何从较低层到较高层进行通信吗?

对于那些想写代码的人,我更喜欢C#。

解决方法

Q1:>域模型是否可以具有比数据库实体(行)更多的属性(或不同的属性)?

可以,因为域模型不是数据库模型。您不应该混合使用它们,因为它们会因不同的原因而变化。域模型(在干净的体系结构中的实体)由于与应用程序无关的业务规则的更改而发生了变化。数据库模型的更改是由于更改了数据保留方式。如果将它们混合使用,则会违反单一责任。

应用程序层无法在没有任何依赖性的情况下调用持久层,因为它不知道持久层中的任何类。

到目前为止,这就是我的理解方式,有人可以给我清楚的解释数据应该如何流动以及如何从较低层到较高层进行通信吗?

有一种方法。这称为依赖反转。如果您要进行结构化编程,则代码将如下所示:

+-----+   f()    +-----+
|  A  |  ----->  |  B  |
+-----+          +-----+

有一个类A调用类f上的方法B

如果您使用的是C#,您将在类using B中看到一个A。如果您使用的是Java,它将是import B。无论您使用哪种编程语言。类B的名称将显示在A中。

但是,如果它是usingimport语句,则表示编译器知道。因此,您具有编译时间依赖性 A-> B

执行代码时,控制流运行时依赖项)也是A-> B

让我们看看另一种方法

+-----+   f()    +------------+       +-------+
|  A  |  ----->  | BInterface | <---- | BImpl |
+-----+          +------------+       +-------+

在这种情况下,A依赖于我在这里称为B的前一个BInterface的抽象,并将实现移至类BImpl来实现该接口。 / p>

运行时控制流仍从{{​​1}}进入A的方法f,但在编译时间 BImplA取决于BImpl,因此,从BInterfaceBImpl的依赖点与控制流。

您可以使用多态来实现。这种方法称为依赖倒置,因为您将依赖倒置,使其指向控制流。

返回您的问题

您的应用程序层应定义一个可用于收集实体的接口。此接口通常称为BInterface。然后,您的数据库层可以实现该Repository(依赖关系倒置)。

在干净的架构中,它看起来像这样

clean architecture

请记住用例和数据库实现之间的双线。这些线称为架构边界。越过这条线的每个依赖项都必须指向同一方向,以遵循干净的体系结构依赖项规则。

还要确保不要犯将特定于实现的东西放在接口中的错误。

接口是一种抽象,因此告诉人们可以做什么,而不是如何完成。

Repository

一种更好的方法是

public interface PersonRepository {

    // WRONG - because the where is usually a part of an SQL or JPQL
    // and thus exposes the implementation.
    public List<Person> findByCriteria(String where);
} 

您可能希望实施更复杂的条件,但要始终保持绝对不要公开实施细节。

,

Q1:领域模型是否可以具有更多属性(或不同 属性)而不是数据库实体(行)?

当然。两种模型可能具有不同的属性。 “持久性端口”(“存储库”)实现,即适配器会将一个模型相互转换。

第二季度:

在大多数情况下,应用程序层需要从 持久层。

应用程序层无法调用持久性 层没有任何依赖关系,因为它不知道任何依赖关系 持久层中的类。

为了从持久层获取数据,应用程序层调用“存储库”(DDD语言),即“持久数据端口”(十六进制体系结构语言)。该存储库(端口)属于域,因此应用程序层称为域层。

数据库适配器实现端口。适配器属于基础结构层,这是可以的,因为基础层不仅取决于应用程序层,还取决于域。

如果您有兴趣,这是我有关六角形建筑的文章:

https://jmgarridopaz.github.io/content/articles.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-