首页 > 编程知识 正文

二叉树的层序遍历java,java中model的作用

时间:2023-05-03 11:54:59 阅读:172679 作者:4246

原标题:你的分层结构没问题吗?

分层结构不是制作文件夹的艺术吗?

注:本文适用于中大型项目。 小项目很有趣。 由于时代的原因,有些词汇的记载可能不那么准确。 欢迎您的指出。

当我开始一个新项目时,我开始做一个折叠的文件夹。 啊,不,那我在做分层结构的设计。 体系结构最后落到现有的计算机操作系统上,其展示形式为分层结构。 毕竟,硅基不如碳基。

但是,为什么我们要进行分层结构的设计呢? 根据层隔离不同的关注点。

So,我开始胡说。

基本思想:分离关注点,划分边界

注:控制器服务模式与MVC模式不同。 那个错误是等同的,引起了体系结构上的一系列错误。

问题:落后的三层体系结构

以前,对大多数项目来说,除了三层分层结构以外,其他部分都是大泥球,也就是随意的代码编排方式。 但我发现,对大多数项目来说,三层分层结构的服务也是一个很大的泥球。 我忘记了三层分层结构的model层也是一个大泥球。 Controller比较好,但对某些项目来说只是个小泥球。

大泥球是指随意制作的杂乱的结构化系统,只有代码的积累和拼凑,会引起许多错误和缺陷。

在当今DDD清洁体系结构流行的今天,三层体系结构不能完全满足现有APP应用的需要,甚至看起来很糟糕。 有这样的问题:

统一管理是恶魔,比如controller文件夹下有很多代码,是散布在各处的模型。

没有明确的角色划分,例如控制器负责服务

肥大化服务与贫血模型

像kafka这样分散在各处的代码等,成为三层后的自由文件的组织方法

但是,为什么呢?

职责(或边界上下文)未明确划分

model层有许多二义性

面向技术的体系结构模型

因此,我们有几个基本的解决方案,或者说道路。

重新定义:消除二义性

当我们谈论服务的时候,我们会谈论同样的服务吗?

当我们谈论model时,我们会谈论同一个model吗?

如果某个语法的某个句子存在两个不同的语法树,那么该语法就是二义语法。

如果有多个不同类型的类,则它们将位于模型包下。 那么,应该去掉model这个包,改为更有意义的名字,比如Entity、* Request、* Response等。 同样,你们开始讨论某个名称的时候,是时候仔细考虑其中的二义性了。

最后,还需要相关领域的名词表。

边界划分:面向业务的体系结构

首先必须说的是:

微服务是面向业务的体系结构。

微服务是面向业务的体系结构。

微服务是面向业务的体系结构。

所以,如果你的微服务划分中出现了一些不同技术维度的服务,你需要好好反思。

为了迎接So、面向业务的体系结构,我们需要采用水平垂直体系结构的方式重新划分体系结构,将各个业务模板的代码聚合到各自的业务模板中,然后将大量的util和common聚合到服务中。 基于其他低级别的模板。

然后,也可以尝试将单个APP分割为微服务器。

但是,我们不应该依赖低层模块。 于是……

关注点分离:界面编程

我们看到了清洁的框架:

其中有一个非常重要的原则:

遵循倒置原则:上层模块不应该依赖下层模块,两者都应该依赖抽象。

这是大多数项目,已经付诸实践。 毕竟,有各种各样的* Service * ServiceImpl。

而且,为了达成这样的目标,对于采用了DDD体系结构的APP应用来说,在我们的domain层的边界上下文中,除了包含自身的entity,vo等之外,应该还附带有repository的抽象。 这样的话,我们的domain层就不依赖了

APP应用分层: DDD和清洁体系结构

所以,让我们来看看问题吧。 这是用GitHub上star数接近15K的Java语言编写的开源CMS,是某个模块的代码目录:

cms-admin/

cms-common/

cms-dao/

cms-job/

cms-rpc-api/

cms-rpc-service/

cms-search/

( cms-web/

这是一种面向技术的APP应用体系结构。 所以,添加新功能时,需要:

在cms-dao模块中添加一个

model 和一个 mapper

在 cms-rpc-service 模块中加一个 service

在 cms-web 模块中中加一个 controller

“完美”,没有什么问题啊。

而随着时间的推移,你现在已经有一个巨大无比的 model 层,修改代码时需要在不同的模块跳转。而不能快速修改相关的代码。甚至于,你无法采用微服务架构,你是一个巨大的单体应用。

为了挽救这样的一个项目,我们不得不尝试做一些事情。

切割基础设施

你的基础设施自开发完成之后,基本不变,而你的业务代码一直在发生变化。

引起技术实现发生变化的原因与引起领域逻辑发生变化的原因显然不同,这就导致基础设施和领域逻辑问题会以不同速率发生变化。——《领域驱动设计模式、原理与实践》

粗心的龙猫来到一个项目一眼看到这么多基础设施相关的目录结构时:

├── controller

├── interceptor

├── jms

├── rocketmq

├── schedule

└── task

有一天,我们又加了一个 Kafka,我们又不新加一个文件夹,而这样的分层设计看上去没有一点组织。然后呢,我们打开目录的时候,无法快速定位到我们的代码。

除了从目录上 infrastructure 包/层,容纳相关的基础设施代码。我们还要考虑到分层上的单一职责,因为需要剥离基础设施与业务代码的关系。所以,为了实现 Clean Architecture 的大业,你还需要一层抽象接口,比如你要访问存储业务相关的数据。那么抽象在你的 domain 中,具体的 RepositoryImpl 实现是在你的基础设施。

离心分离模型

在一个系统中,你会存在这么一些不同的 model:

(PS:部分描述可能不准确,欢迎指正)

与数据库表结构对应的 DO( Data Object)/ PO(Persistant Object)。

查询数据的 Query、Request。

对外传输的对象:DTO( Data Transfer Object)。

业务层之间的数据对象:VO(Value Object) / BO(Business Object)。

访问数据库的:DAO (Data Access Object数据访问对象)。

以及我们想要的 DDD 中的实体 Entity

还有其它的 POJO( Plain Ordinary Java Object)

但是它们都是 model,所以它们都被扔到 model 中……,又或者是 bean 中……。导致,你有了一个巨大比的 model 层。

所以,在 DDD 又或者是 Clean Architecture,我们重新命名了不同的模式:

使用 Command / Request 作为输入参数。其中的 Command 模式在完成后需要发出对应的 Event。

使用 Response / DTO / Representation 作为返回结果。

对 Entity 大家保持了一致的意见

还有 PO / DO 作为作为数据库的存储模型

DAO 作为数据库的访问模型

不过,其实你只要不再让使用 model 和 bean,相似会有更多地收获。

以领域为核心,丰富行为

当完成了大坨的移动文件夹操作之后,我们来到了最麻烦和复杂的一部分。

我们需要对领域模型进行重新建模,重新规划 model 和 service,让 model 变成了富血模型。也许,你需要一场 Event Storming,才能完成真正意义的事件风暴建模。不过,步骤上也不会有太多的差异。

重新划分包。即在保持业务不中断的情况下重构,以让新的代码运行在新的架构上。

分析抽象领域模型

编写 API 测试,保证现有的功能

编写抽象接口,进行依赖反转

拆分 service 层,重构代码。将行为绑定于是领域对象上。

其它的情况,还要进行 case by case 的分析。

剩下的呢?

共享的业务逻辑,可以采用 sharedkernel,或者其它模式来处理。

待继续补充。

代码共用分层:功能内聚

创建通用的共享组件导致了一系列问题,比如耦合、协调难度和复杂度增加。

当我看到一个个巨大的 common 包时,我开始痛恨 common、 base、 util这些该死的包,还有它们目录下统一管理的 bean。我们真的已经把它们用烂了,所以你应该重新审视一下你的项目代码。

所以,从这种意义上来说: 复用与低耦合,本身存在一定的互斥关系。

base 下的 base

过去,我曾经重构过一个 base 项目的代码,正是这次重构让我意识到 base 并不是一个好东西。如果在项目中已经抽取出了一个 base 模块,那么这个模块下是不应该存在 base 这样的业务逻辑。而且,base 这个东西导致了一个问题是,只要是共用的东西就会不加思索的扔到 base 中。

你会有一个 base 的包,放着各种抽象接口,但是你需要一个更好的名字,比如 concepts,比如 support。

总之,你不应该存在 base 模块,让开发人员思考一下哪去放新的类。

无比臃肿的 bean 和 model

“这本身是怪不得程序员的,要怪就怪该死的 Java 语言。”

转而,我开始考虑一个问题,当个包(文件夹)下的文件数是否不应该超过一定的数量?

如果一个包下的类数,超过一定的范围,那么我们应该考虑是否存在职责相似的类。

这部分可以参考上一部分的离心分离模型。

什么不是 common

common 这个名字真的很烂,比 base 和 model 更烂。

一旦你从项目中拆出了一个 common 模块,那只会有一个结果,你将得到一个 5G 时代的 jar 包。甚至于,你看到有一块代码在 IDE 中是灰色的、未使用的,你也不敢轻易去删除这些代码。直到有一天,这个 common 包构建出来的大小有 10M、20M,而你只需要引用一个 AESUtil 的时候,你才发现了问题:原本几十 K 的 hello, world,现在变成了几十 M。

不要事先创建 common 模块,你可能不会有这个模块。

任何的水平分层拆分应用,在项目复杂化的今天都是不靠谱的。

谁用谁管理,而不是觉得是 common 就扔 common 模块。

它真是个 util 吗?

哦,不,它是个恶魔,因为它是 util。

你会往 xxUtil 不加思索地扔入逻辑,正如你会往 common/bean 中扔入所有的 model,直次有一天,你拥有一个巨大无比的 base、common 代码。

大多数情况下,所有和业务相关的 Util 都存在一定的问题,如 CaptchaUtil,它要么应该划到自己的上下文中去,要么扔到诸如于 domain/shared 等共享上下文,而不是和其它 util 放到一起。

而诸如 FileUtil、DateUtil、RedisUtil、JdbcUtil 这些都可以说是基础设施相关的部分,它们可以划到 infrastructure/file 又或者是 infrastructure/date 目录下,而不是统一的管理这些 util。

如 StackOverflow 的相关问题所列,我们还有诸如 Coordinator、Builder、Writer、Reader、Handler、Container、Protocol、Target、Converter、Controller、View、Factory、Entity、Bucket 等名称。

试着干掉 Util,你将收获更多的类,笑~。

需要个例子?

看看 Spring Framework 的源码的分层结构,如 Spring Orm:

└── orm

├── ObjectOptimisticLockingFailureException .java

├── ObjectRetrievalFailureException .java

├── hibernate5a/

├── jpa/

└── package -info.java

又或者是 spring-context 下的目录分层结构:

└── springframework

├── cache

│ ├── annotation

│ ├── concurrent

│ ├── config

│ ├── interceptor

│ └── support

├── context

│ ├── annotation

│ ├── config

│ ├── event

│ ├── expression

│ ├── i18n

│ ├── index

│ ├── support

│ └── weaving

它们都在自己的限界上下文内,维护自己的 annotaion、bean、support、i18n 等等的包。

分层架构重构

所以,我们可以尝试这么去做架构重构

分析、诊断现有项目结构

划分新的分层架构

功能测试

使用抽象解耦依赖

进行细粒度的代码重构

重新划分领域服务还有吗?

不要预先设计,而是定义原则与规范。

以简单的设计开始,在生命周期中演进架构。

以多个 common 包,替代统一的 common 包

TBC。结论

那么,我们怎么才能做好分层架构呢?

by experience。

哦,不对,DDD 大法好。返回搜狐,查看更多

责任编辑:

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。