DDD之六边形架构(Hexagonal Architecture)

领域驱动设计系列文章,点击上方合集↑

六边形架构(Hexagonal Architecture),也被称为端口和适配器架构(Ports and Adapters Architecture),是一种软件架构模式,用于构建可测试、可维护和灵活的应用程序。

1. 简介

六边形架构的设计思想源于Alistair Cockburn在2005年提出的“六边形关系图”理论。在这个理论中,软件系统被视为一个六边形,其中有三组组件构成:核心业务逻辑(Domain),输入和输出端口(Ports)以及适配器(Adapters)。这些组件通过一系列接口进行交互,实现内部的业务逻辑,并通过端口和适配器与外部系统进行交互。

  • 上图来自《实现领域驱动》这本书

2. 主要组件和原则

  1. 核心业务逻辑(Domain):核心业务逻辑是应用程序的核心部分,其中包含领域对象、实体、值对象、领域服务等。它独立于具体的技术实现,通过领域模型去描述和解决业务问题。

  2. 输入和输出端口(Ports):输入和输出端口定义了应用程序与外部世界的交互接口。输入端口用于接收来自外部系统的请求,输出端口用于向外部系统发送结果或状态更新。这些端口提供了抽象层,使核心业务逻辑与具体的外部依赖解耦。

  3. 适配器(Adapters):适配器是连接输入和输出端口与具体实现的桥梁。它们负责将外部世界的请求转换为适合核心业务逻辑处理的数据,并将结果适配为外部系统能够理解的形式。适配器可以是数据库、消息队列、外部服务库或任何其他与外部系统进行交互的方式。

在六边形架构中,核心业务逻辑位于六边形的中心,它不依赖于具体的外部实现。输入和输出端口围绕核心逻辑,提供与外部系统的交互接口。适配器将请求和响应合理地转换为适合核心逻辑的形式。这种架构模式使得我们可以更容易地替换、测试和调整外部依赖,因为核心逻辑与外部实现解耦。

3. 构建步骤

  1. 定义领域模型和核心业务逻辑:通过DDD的原则,识别并定义核心业务领域,并建立一个独立于技术实现的领域模型。

  2. 定义输入和输出端口:识别应用程序与外部系统的交互点,并设计相应的端口接口。这些端口应该抽象、可扩展和可测试。

  3. 实现适配器:根据具体的外部系统,实现适配器将外部请求转换为领域模型可以理解的格式,并将结果转换为外部系统可以处理的格式。

  4. 配置依赖注入(Dependency Injection):通过依赖注入,将适配器注入到核心业务逻辑中,确保它们能够无缝地协作。

  5. 编写测试:通过单元测试和整体测试,确保核心业务逻辑与外部系统的交互正常,并满足业务需求。

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;
    }

    @PostMapping
    public ResponseEntity<Product> addProduct(@RequestBody Product product) {
        Product addedProduct = productService.addProduct(product);
        return ResponseEntity.ok(addedProduct);
    }

    @GetMapping
    public 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 {

    @Bean
    public ProductService productService(ProductServiceFeignClient productServiceFeignClient) {
        return new ProductServiceAdapter(productServiceFeignClient);
    }
}

4.5 配置文件

在Spring Cloud中,还需要配置各个微服务的相关信息。

spring:
  application:
    name: product-service

product-service:
  server:
    port: 8080

通过以上代码演示,我们将商品管理的核心业务逻辑与外部系统的交互逻辑进行了解耦,并支持了系统的扩展和替换。核心层的设计遵循领域驱动设计的原则,外围层通过适配器与外部系统交互,实现了六边形架构。

当我们需要对商品管理进行扩展时,可以通过修改核心层的代码来实现。当需要修改与外部系统的交互方式时,只需要修改适配器的实现即可,而不需要改动核心层的代码。

5. 结语

通过六边形架构,我们可以将关注点分离开来,提高系统的可测试性、可维护性和可扩展性。同时,该架构也使得领域驱动设计中的概念更加清晰,并促进了团队间的协作和集成。


关注微信公众号:“小虎哥的技术博客”,让我们一起成为更优秀的程序员❤️!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小虎哥的技术博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值