如何结构化我们的代码

软件设计最佳实践,探讨按层、按特性和六边形架构/端口和适配器的代码结构。

在这篇文章中,我将探讨如何组织我们的代码并讨论最佳实践,涵盖三种不同的方法:按层、按特性和六边形架构/端口和适配器,以及它们的优缺点。

在探讨不同的代码结构方法之前,我们需要了解基本的软件设计原则:

?内聚性(Cohesion):指模块内部的类彼此相关的程度。?耦合性(Coupling):指不同模块之间的依赖程度。

1*2Q8ye2K8hYRtNOMHWxoOBQ.png

?模块性(Modularity):指软件系统被分成独立模块的程度。每个模块封装了一组特定的功能,并被设计成能够独立工作,通过明确定义的接口与其他模块交互。?抽象化(Abstraction):隐藏实现细节,只通过接口暴露必要的功能。?关注点分离(Separation of Concerns):具有明确定义的各个部分,每个部分处理特定的关注点。?封装性(Encapsulation):将数据和方法捆绑到单个模块或类中,以隐藏内部细节。

让我们更仔细地看看内聚性和耦合性?

内聚性描述软件的 关注点有多集中。它与单一职责原则密切相关。

?高内聚性 意味着模块内的类彼此密切相关,并共享一个共同的、明确定义的目的。?低内聚性 意味着模块内的类关系不紧密,缺乏明确的目的,具有无关的责任。

遵循的最佳实践是追求高内聚性和松耦合

如何结构化我们的代码
1*6DpCfIP-T09sZBfxu8G2DA.png

松散的耦合被认为是计算机系统良好结构和良好设计的迹象,与高内聚性结合使用时,可实现高可读性和可维护性。

如何结构化我们的代码
1*WVS54T-5rqEvL7xf1AeADA.png

现在,让我们探讨不同的代码组织方式。首先,我将介绍按层组织,然后是按特性组织,对比这两者。之后,我们将探讨六边形架构/端口和适配器模式。

如何结构化我们的代码
1*fmBZBkeP4RAmM9DwFoynyQ.png

按层组织

它表示一个项目结构,其中类被组织到多个层中,每个层负责一组特定的功能。

src├── main│   ├── java│   │   └── com│   │       └── app│   │           ├── service│   │           │   └── UserService.java│   │           │   └── OrderService.java│   │           │   └── ProductService.java│   │           ├── domain│   │           │   └── User.java│   │           │   └── Order.java│   │           │   └── Product.java│   │           ├── repository│   │           │   └── UserRepository.java│   │           │   └── OrderRepository.java│   │           │   └── ProductRepository.java│   │           ├── controller│   │           │   └── UserController.java│   │           │   └── OrderController.java│   │           │   └── ProductController.java

典型的层包括:

1.表示层(Presentation Layer):负责处理用户交互并向用户呈现信息。通常包括与用户界面、控制器和视图相关的组件。2.服务层(Service Layer):包含业务逻辑并提供演示层所需的数据。3.领域包(Domain Package):该包包含领域实体。4.数据访问层(Data Access Layer):该层处理数据到/从数据库的持久化和检索。5.基础设施包(Infrastructure Package):该包提供支持应用程序操作的服务。它可能包括用于日志记录、配置、安全等横切关注点的组件。

使用 按层组织 的一些缺点:

?低内聚性:不相关的类被组合到同一个包中。?高耦合性?封装性差:大多数类是公共的,因此我们无法将类设置为包私有,因为它们在其他层中是需要的。?低模块性:由于每个包包含与特定层相关的类,因此很难将代码分解为后来的微服务。?可维护性差:由于类散布在不同的包中,很难找到正在寻找的类。?它促进了数据库驱动设计,而不是领域驱动设计。

按特性组织

它表示一种根据功能或特性而不是层次结构组织代码的结构。在这种方法中,每个包代表一个独特且独立的功能。

目标是将与特定特性相关的所有组件(如控制器、服务、存储库和领域类)组合到一个包中。

src├── main│   ├── java│   │   └── com│   │       └── app│   │           ├── user│   │           │   ├── UserController.java│   │           │   ├── UserService.java│   │           │   └── UserRepository.java│   │           ├── order│   │           │   ├── OrderController.java│   │           │   ├── OrderService.java│   │           │   └── OrderRepository.java│   │           ├── product│   │           │   ├── ProductController.java│   │           │   ├── ProductService.java│   │           │   └── ProductRepository.java

使用此结构的一些好处包括:

?高内聚性?低耦合性?强封装性:允许某些类将其访问修饰符设置为包私有而不是公共。?高模块性:由于每个包包含与特定功能相关的类,因此很容易将代码分解为后来的微服务。?可维护性:减少了在包之间导航的需求,因为所有与特性相关的类都在同一个包中。?促进了领域驱动设计

六边形架构/端口和适配器模式

六边形架构,也称为端口和适配器,是由阿利斯泰尔·科克本博士在他2005年的一篇文章中介绍的软件架构模式。[1]

该模式通过保持核心业务逻辑独立于外部细节,并不紧密耦合于数据库、用户界面或外部服务等外部依赖,促进了关注点的隔离/分离。

这使得测试、维护和发展系统更加容易。

1*wF_VJcN5dpwCQB_sx1z2_w.png

在此模式中:

1.领域/核心(Domain / Core)代表应用程序的业务逻辑或领域(应用程序的核心)。2.端口(Ports)端口是核心定义的接口,允许与外部组件进行交互。这些可以包括服务、存储库或任何外部依赖的接口。3.适配器(Adapters)适配器是端口的实现。它们将核心应用程序连接到数据库、用户界面和外部服务等外部组件。适配器可以针对不同的技术或协议进行特定的实现。4.主要操作者(Primary actors)系统的使用者,如webhook、UI请求或测试脚本。5.次要操作者(Secondary actors)被应用程序使用的这些服务是 Repository(例如数据库)或 Recipient(例如消息队列)。

1*AUdml5HCo92xf8WgHkZfRA.gif

六边形形状:

六边形形状象征着核心应用程序位于中心,周围是适配器。这个形状代表了核心与其外部依赖之间的明确分离。

顶级包结构应如下所示:

src/main/  java    mina      dev        <servicename>          adapters          config          core          <ServiceApplication>.java

根包应只包含包:coreadaptersconfig

?core 包含服务的所有领域逻辑。它可以包含子包。?端口应该位于 core 包中:端口只是由核心声明的要调用或由适配器实现的接口。?adapters 包含所有适配器实现代码。它可以包含子包以按单个适配器或技术组织适配器代码。?config 包含用于连接不同组件的配置类。

包依赖规则:

?根包可以依赖于所有其他包。?config 包可以依赖于 core 和 adapters。?adapters 可以依赖于 core,但不可以依赖于 config。?core 不得依赖于其他任何包。

希望这篇文章能够帮助您更好地理解不同的代码结构。

引用链接

[1] 软件架构模式。: https://alistair.cockburn.us/hexagonal-architecture/


原创文章,作者:小技术君,如若转载,请注明出处:https://www.sudun.com/ask/34027.html

(0)
小技术君's avatar小技术君
上一篇 2024年4月8日 上午9:39
下一篇 2024年4月8日 上午9:41

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注