领域驱动设计系列文章,点击上方合集↑
六边形架构(Hexagonal Architecture),也被称为端口和适配器架构(Ports and Adapters Architecture),是一种软件架构模式,用于构建可测试、可维护和灵活的应用程序。
1. 简介
六边形架构的设计思想源于Alistair Cockburn在2005年提出的“六边形关系图”理论。在这个理论中,软件系统被视为一个六边形,其中有三组组件构成:核心业务逻辑(Domain),输入和输出端口(Ports)以及适配器(Adapters)。这些组件通过一系列接口进行交互,实现内部的业务逻辑,并通过端口和适配器与外部系统进行交互。
- 上图来自《实现领域驱动》这本书
2. 主要组件和原则
-
核心业务逻辑(Domain):核心业务逻辑是应用程序的核心部分,其中包含领域对象、实体、值对象、领域服务等。它独立于具体的技术实现,通过领域模型去描述和解决业务问题。
-
输入和输出端口(Ports):输入和输出端口定义了应用程序与外部世界的交互接口。输入端口用于接收来自外部系统的请求,输出端口用于向外部系统发送结果或状态更新。这些端口提供了抽象层,使核心业务逻辑与具体的外部依赖解耦。
-
适配器(Adapters):适配器是连接输入和输出端口与具体实现的桥梁。它们负责将外部世界的请求转换为适合核心业务逻辑处理的数据,并将结果适配为外部系统能够理解的形式。适配器可以是数据库、消息队列、外部服务库或任何其他与外部系统进行交互的方式。
在六边形架构中,核心业务逻辑位于六边形的中心,它不依赖于具体的外部实现。输入和输出端口围绕核心逻辑,提供与外部系统的交互接口。适配器将请求和响应合理地转换为适合核心逻辑的形式。这种架构模式使得我们可以更容易地替换、测试和调整外部依赖,因为核心逻辑与外部实现解耦。
3. 构建步骤
-
定义领域模型和核心业务逻辑:通过DDD的原则,识别并定义核心业务领域,并建立一个独立于技术实现的领域模型。
-
定义输入和输出端口:识别应用程序与外部系统的交互点,并设计相应的端口接口。这些端口应该抽象、可扩展和可测试。
-
实现适配器:根据具体的外部系统,实现适配器将外部请求转换为领域模型可以理解的格式,并将结果转换为外部系统可以处理的格式。
-
配置依赖注入(Dependency Injection):通过依赖注入,将适配器注入到核心业务逻辑中,确保它们能够无缝地协作。
-
编写测试:通过单元测试和整体测试,确保核心业务逻辑与外部系统的交互正常,并满足业务需求。
4. 具体代码演示
假设我们正在开发一个电商应用,需要实现商品管理的功能,包括添加商品、查询商品等操作。我们将使用Spring Cloud作为微服务框架,将核心层和外围层分离,使用适配器进行交互。
4.1 核心层的设计
首先,我们在核心层定义商品的领域模型和业务逻辑:
public class Product {private String id;private String name;private double price;// getters and setters
}public interface ProductService {Product addProduct(Product product);List<Product> getAllProducts();Product getProductById(String id);
}
4.2 外围层的设计
接下来,我们设计外围层,定义与外部系统的交互接口。
@RestController
@RequestMapping("/api/products")
public class ProductController {private final ProductService productService;public ProductController(ProductService productService) {this.productService = productService;}@PostMappingpublic ResponseEntity<Product> addProduct(@RequestBody Product product) {Product addedProduct = productService.addProduct(product);return ResponseEntity.ok(addedProduct);}@GetMappingpublic ResponseEntity<List<Product>> getAllProducts() {List<Product> products = productService.getAllProducts();return ResponseEntity.ok(products);}@GetMapping("/{id}")public ResponseEntity<Product> getProductById(@PathVariable String id) {Product product = productService.getProductById(id);return ResponseEntity.ok(product);}
}
4.3 适配器的实现
我们使用Spring Cloud中的Feign客户端作为适配器,与其他微服务进行通信。
@FeignClient(name = "product-service", url = "http://localhost:8080")
// 这里假设商品服务的URL为http://localhost:8080
public interface ProductServiceFeignClient {@PostMapping("/api/products")Product addProduct(@RequestBody Product product);@GetMapping("/api/products")List<Product> getAllProducts();@GetMapping("/api/products/{id}")Product getProductById(@PathVariable String id);
}
4.4 依赖注入与配置
最后,我们通过依赖注入将适配器注入到核心业务逻辑中,使用Spring Cloud进行配置管理。
@Configuration
public class ProductServiceConfiguration {@Beanpublic ProductService productService(ProductServiceFeignClient productServiceFeignClient) {return new ProductServiceAdapter(productServiceFeignClient);}
}
4.5 配置文件
在Spring Cloud中,还需要配置各个微服务的相关信息。
spring:application:name: product-serviceproduct-service:server:port: 8080
通过以上代码演示,我们将商品管理的核心业务逻辑与外部系统的交互逻辑进行了解耦,并支持了系统的扩展和替换。核心层的设计遵循领域驱动设计的原则,外围层通过适配器与外部系统交互,实现了六边形架构。
当我们需要对商品管理进行扩展时,可以通过修改核心层的代码来实现。当需要修改与外部系统的交互方式时,只需要修改适配器的实现即可,而不需要改动核心层的代码。
5. 结语
通过六边形架构,我们可以将关注点分离开来,提高系统的可测试性、可维护性和可扩展性。同时,该架构也使得领域驱动设计中的概念更加清晰,并促进了团队间的协作和集成。
关注微信公众号:“小虎哥的技术博客”,让我们一起成为更优秀的程序员❤️!