软件设计最佳实践,探讨按层、按特性和六边形架构/端口和适配器的代码结构。
在这篇文章中,我将探讨如何组织我们的代码并讨论最佳实践,涵盖三种不同的方法:按层、按特性和六边形架构/端口和适配器,以及它们的优缺点。
在探讨不同的代码结构方法之前,我们需要了解基本的软件设计原则:
?内聚性(Cohesion):指模块内部的类彼此相关的程度。?耦合性(Coupling):指不同模块之间的依赖程度。
?模块性(Modularity):指软件系统被分成独立模块的程度。每个模块封装了一组特定的功能,并被设计成能够独立工作,通过明确定义的接口与其他模块交互。?抽象化(Abstraction):隐藏实现细节,只通过接口暴露必要的功能。?关注点分离(Separation of Concerns):具有明确定义的各个部分,每个部分处理特定的关注点。?封装性(Encapsulation):将数据和方法捆绑到单个模块或类中,以隐藏内部细节。
让我们更仔细地看看内聚性和耦合性?
内聚性描述软件的 关注点有多集中。它与单一职责原则密切相关。
?高内聚性 意味着模块内的类彼此密切相关,并共享一个共同的、明确定义的目的。?低内聚性 意味着模块内的类关系不紧密,缺乏明确的目的,具有无关的责任。
遵循的最佳实践是追求高内聚性和松耦合。
松散的耦合被认为是计算机系统良好结构和良好设计的迹象,与高内聚性结合使用时,可实现高可读性和可维护性。
现在,让我们探讨不同的代码组织方式。首先,我将介绍按层组织,然后是按特性组织,对比这两者。之后,我们将探讨六边形架构/端口和适配器模式。
按层组织
它表示一个项目结构,其中类被组织到多个层中,每个层负责一组特定的功能。
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.领域/核心(Domain / Core)代表应用程序的业务逻辑或领域(应用程序的核心)。2.端口(Ports)端口是核心定义的接口,允许与外部组件进行交互。这些可以包括服务、存储库或任何外部依赖的接口。3.适配器(Adapters)适配器是端口的实现。它们将核心应用程序连接到数据库、用户界面和外部服务等外部组件。适配器可以针对不同的技术或协议进行特定的实现。4.主要操作者(Primary actors)系统的使用者,如webhook、UI请求或测试脚本。5.次要操作者(Secondary actors)被应用程序使用的这些服务是 Repository(例如数据库)或 Recipient(例如消息队列)。
六边形形状:
六边形形状象征着核心应用程序位于中心,周围是适配器。这个形状代表了核心与其外部依赖之间的明确分离。
顶级包结构应如下所示:
src/main/
java
mina
dev
<servicename>
adapters
config
core
<ServiceApplication>.java
根包应只包含包:core
、adapters
和config
。
?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