六边形软件架构模式(Architecture Pattern)
文章目录
- 一 六边形架构
- 1.1 六边形架构的核心思想
- 1.2 六边形架构的主要组成部分
- 1.3 六边形架构的优点
- 二 案例订单管理系统
- 2.1 六边形架构设计
- 2.2 Java代码实现
- 2.2.1 结构设计
- 2.2.2 领域模型(Domain Model)
- 2.2.3 业务服务接口(端口)
- 2.2.3 应用用例层(协调业务流程)
- 2.2.4 输出端口(Repository接口)
- 2.2.5 输出适配器(JPA Repository实现)
- 2.2.6 输入适配器(REST Controller)
- 2.2.7 启动类
- 三 总结
一 六边形架构
- 六边形架构(Hexagonal Architecture),也称为“端口与适配器架构”(Ports and Adapters Architecture),是一种软件架构模式,旨在提升软件系统的可维护性、可测试性和灵活性。它最早由Alistair Cockburn提出,目的是通过将应用程序的核心逻辑与外围技术(如数据库、用户界面、外部服务等)解耦,减少系统对外部依赖的耦合度,从而使系统更容易更换和扩展。
1.1 六边形架构的核心思想
六边形架构将系统分为两部分:
- 应用核心(Domain/Business Logic): 这是系统的核心业务逻辑,独立于任何外部技术。它只关注业务规则和流程。
- 外围接口(Ports and Adapters): 通过“端口”定义系统与外部世界交互的接口,例如输入端口(供用户界面或其他系统调用)和输出端口(供数据库、消息队列等使用)。“适配器”则是实现这些端口的具体代码,负责将外部系统的调用转换为应用核心能够理解的形式,反之亦然。
1.2 六边形架构的主要组成部分
- Domain(领域/业务逻辑): 六边形中心,包含业务规则和逻辑。
- Ports(端口): 应用核心对外提供的接口,定义了核心与外部交互的契约。
- Adapters(适配器): 实现端口接口的具体代码,负责与外部系统(数据库、UI、外部服务)通信。
- Application(应用服务): 介于领域模型和端口之间,处理业务用例的协调。
- 用户界面(UI)和外部系统: 通过适配器访问核心逻辑。
1.3 六边形架构的优点
- 解耦性强: 业务逻辑不依赖具体技术实现,便于替换外部组件。
- 可测试性好: 业务逻辑可以单独测试,外围适配器可以通过模拟端口接口来测试。
- 灵活扩展: 可以方便地添加新的适配器来支持不同的UI、数据库或外部服务。
- 遵循单一职责原则: 各层职责分明,代码结构清晰。
二 案例订单管理系统
2.1 六边形架构设计
假设有一个订单管理系统:
- 核心业务逻辑: 订单的创建、修改、计算价格等。
- 输入端口: 定义订单创建的接口(如
createOrder()
)。 - 输入适配器: 通过REST API接收请求,调用输入端口。
- 输出端口: 定义订单存储的接口(如
saveOrder()
)。 - 输出适配器: 实现数据持久化,如MySQL数据库的实现。
说明
- 核心业务逻辑层是整个系统的中心,包含订单领域模型和业务逻辑接口及实现。
- 输入适配器层负责接收外部请求(如REST API),调用核心的输入端口。
- 输出适配器层负责实现核心业务依赖的输出端口,如数据库存储。
- 核心业务逻辑通过端口与外界通信,实现解耦。
- 核心业务逻辑只通过端口与外界交互,具体的存储方式和用户界面可以随时替换而不影响核心代码。
2.2 Java代码实现
- 基于 六边形架构 的思想,使用 Java Spring Boot 框架,给出一个简化版的订单管理系统示例代码。示例中会体现:领域层(核心业务逻辑)、端口(接口)、适配器(输入、输出适配器)。
2.2.1 结构设计
com.yang.ordersystem
├── domain # 领域模型和业务逻辑
│ ├── model
│ │ └── Order.java
│ └── service
│ └── OrderService.java (核心业务接口)
│
├── application # 应用服务层(用例)
│ └── OrderUseCase.java
│
├── adapter
│ ├── inbound # 输入适配器 (如 REST Controller)
│ │ └── OrderController.java
│ └── outbound # 输出适配器 (如数据库存储)
│ ├── OrderRepository.java (端口接口)
│ └── OrderRepositoryImpl.java (数据库实现)
│
└── OrdersystemApplication.java
- 输入适配器
OrderController
通过 REST 接口接收请求,调用业务接口。 - 业务接口
OrderService
定义业务操作的契约。 - 领域模型
Order
独立于框架和技术。 - 应用用例层
OrderUseCase
实现业务逻辑,依赖输出端口OrderRepository
。 - 输出适配器
OrderRepositoryImpl
负责和数据库交互。
这样,系统核心业务和外部技术解耦,符合六边形架构思想,便于维护和扩展。
2.2.2 领域模型(Domain Model)
package com.yang.ordersystem.domain.model;import java.util.UUID;public class Order {private String id;private String product;private int quantity;private double price;public Order(String product, int quantity, double price) {this.id = UUID.randomUUID().toString();this.product = product;this.quantity = quantity;this.price = price;}// 省略 getter/setter
}
2.2.3 业务服务接口(端口)
package com.yang.ordersystem.domain.service;import com.yang.ordersystem.domain.model.Order;public interface OrderService {Order createOrder(String product, int quantity, double price);
}
2.2.3 应用用例层(协调业务流程)
package com.yang.ordersystem.application;import com.yang.ordersystem.domain.model.Order;
import com.yang.ordersystem.domain.service.OrderService;
import com.yang.ordersystem.adapter.outbound.OrderRepository;
import org.springframework.stereotype.Service;@Service
public class OrderUseCase implements OrderService {private final OrderRepository orderRepository;public OrderUseCase(OrderRepository orderRepository) {this.orderRepository = orderRepository;}@Overridepublic Order createOrder(String product, int quantity, double price) {// 业务校验示例if (quantity <= 0) {throw new IllegalArgumentException("Quantity must be greater than zero");}if (price <= 0) {throw new IllegalArgumentException("Price must be greater than zero");}Order order = new Order(product, quantity, price);orderRepository.save(order);return order;}
}
2.2.4 输出端口(Repository接口)
package com.yang.ordersystem.adapter.outbound;import com.yang.ordersystem.domain.model.Order;public interface OrderRepository {void save(Order order);
}
2.2.5 输出适配器(JPA Repository实现)
- 假设数据库表结构已经准备好。
package com.yang.ordersystem.adapter.outbound;import com.yang.ordersystem.domain.model.Order;
import org.springframework.stereotype.Component;import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.beans.factory.annotation.Autowired;// JPA 实体
@Entity
@Table(name = "orders")
class OrderEntity {@Idprivate String id;private String product;private int quantity;private double price;// 省略构造函数和getter/setterpublic OrderEntity() {}public OrderEntity(Order order) {this.id = order.getId();this.product = order.getProduct();this.quantity = order.getQuantity();this.price = order.getPrice();}public String getId() { return id; }public String getProduct() { return product; }public int getQuantity() { return quantity; }public double getPrice() { return price; }public void setId(String id) { this.id = id; }public void setProduct(String product) { this.product = product; }public void setQuantity(int quantity) { this.quantity = quantity; }public void setPrice(double price) { this.price = price; }
}// Spring Data JPA接口
interface SpringDataOrderRepository extends JpaRepository<OrderEntity, String> {
}// 适配器实现
@Component
public class OrderRepositoryImpl implements OrderRepository {private final SpringDataOrderRepository springDataOrderRepository;@Autowiredpublic OrderRepositoryImpl(SpringDataOrderRepository springDataOrderRepository) {this.springDataOrderRepository = springDataOrderRepository;}@Overridepublic void save(Order order) {OrderEntity entity = new OrderEntity(order);springDataOrderRepository.save(entity);}
}
2.2.6 输入适配器(REST Controller)
package com.yang.ordersystem.adapter.inbound;import com.yang.ordersystem.domain.model.Order;
import com.yang.ordersystem.domain.service.OrderService;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/orders")
public class OrderController {private final OrderService orderService; // 依赖于业务接口public OrderController(OrderService orderService) {this.orderService = orderService;}// 创建订单接口@PostMappingpublic Order createOrder(@RequestBody CreateOrderRequest request) {return orderService.createOrder(request.getProduct(), request.getQuantity(), request.getPrice());}// 请求体DTOpublic static class CreateOrderRequest {private String product;private int quantity;private double price;public String getProduct() {return product;}public int getQuantity() {return quantity;}public double getPrice() {return price;}public void setProduct(String product) {this.product = product;}public void setQuantity(int quantity) {this.quantity = quantity;}public void setPrice(double price) {this.price = price;}}
}
2.2.7 启动类
package com.yang.ordersystem;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class OrdersystemApplication {public static void main(String[] args) {SpringApplication.run(OrdersystemApplication.class, args);}
}
三 总结
- 六边形架构是一种强调依赖反转和模块解耦的架构设计理念,通过“端口”和“适配器”模式,将业务逻辑与外部技术分离,提升系统的灵活性、可测试性和可维护性,特别适用于复杂、长期维护的软件系统。