【架构实战】六边形架构与整洁架构实战

一、架构演进概述

随着业务复杂度增加,软件架构也在不断演进:

架构演进历程:

  • 分层架构 → 六边形架构 → 整洁架构 → 微服务架构
  • 核心目标:实现高内聚、低耦合

架构质量评估:

  • 独立性:框架、数据库、UI的可替换性
  • 可测试性:业务逻辑可独立测试
  • 可维护性:代码易于理解和修改

二、六边形架构(Hexagonal Architecture)

1. 核心理念

复制代码
六边形架构,又称端口与适配器(Ports and Adapters),由Alistair Cockburn提出。

核心思想:
- 业务逻辑处于核心位置
- 通过端口与外部世界交互
- 适配器负责协议转换

2. 架构图

复制代码
                    ┌─────────────────────────────────┐
                    │          外部世界                 │
                    │  (数据库、Web UI、外部服务)        │
                    └─────────────┬───────────────────┘
                                  │
                    ┌─────────────▼───────────────────┐
                    │           适配器层               │
                    │  ┌─────────────┬─────────────┐ │
                    │  │   驱动适配器 │  驱动适配器  │ │
                    │  │ (Primary)   │ (Primary)   │ │
                    │  └──────┬──────┴──────┬──────┘ │
                    └─────────┼─────────────┼────────┘
                              │             │
                    ┌─────────▼─────────────▼─────────┐
                    │            端口层               │
                    │   (输入端口)    (输出端口)       │
                    │  ┌─────────────┬─────────────┐ │
                    │  │             │             │ │
                    │  └──────┬──────┴──────┬──────┘ │
                    └─────────┼─────────────┼────────┘
                              │             │
                    ┌─────────▼─────────────▼─────────┐
                    │          应用层                 │
                    │      (用例/服务编排)            │
                    └─────────┬─────────────────────┘
                              │
                    ┌─────────▼─────────────────────┐
                    │          领域层                │
                    │   (核心业务逻辑、实体、值对象)   │
                    └─────────────────────────────────┘

3. 核心概念

端口(Port):

  • 定义了系统与外部交互的方式
  • 分为输入端口(驱动端口)和输出端口(被驱动端口)
  • 端口是接口,不包含实现

适配器(Adapter):

  • 负责实现端口定义的接口
  • 处理外部协议和格式转换
  • 适配器可以随时替换

4. 代码实现

领域层(核心):

java 复制代码
// 领域实体
public class Order {
    private OrderId id;
    private CustomerId customerId;
    private OrderStatus status;
    private List<OrderItem> items;
    
    public void addItem(Product product, int quantity) {
        if (status != OrderStatus.DRAFT) {
            throw new BusinessException("只有草稿状态可以添加商品");
        }
        items.add(new OrderItem(product, quantity));
    }
    
    public void submit() {
        if (items.isEmpty()) {
            throw new BusinessException("订单不能为空");
        }
        this.status = OrderStatus.SUBMITTED;
    }
}

// 领域服务
public class OrderDomainService {
    public void validateOrder(Order order) {
        // 业务规则验证
    }
}

输入端口(Driving Port):

java 复制代码
// 输入端口接口(由应用层或领域层定义)
public interface OrderInputPort {
    
    OrderDTO createOrder(CreateOrderCommand command);
    
    OrderDTO updateOrder(Long orderId, UpdateOrderCommand command);
    
    void cancelOrder(Long orderId);
    
    OrderDTO getOrder(Long orderId);
    
    Page<OrderDTO> listOrders(OrderQuery query);
}

输出端口(Driven Port):

java 复制代码
// 输出端口接口(由应用层定义,由基础设施实现)
public interface OrderRepository {
    Order findById(OrderId id);
    Order save(Order order);
    void delete(OrderId id);
}

public interface ProductRepository {
    Product findById(ProductId id);
    List<Product> findByIds(List<ProductId> ids);
}

public interface EventPublisher {
    void publish(DomainEvent event);
}

public interface IdGenerator {
    OrderId generateId();
}

应用层(用例):

java 复制代码
// 应用服务实现输入端口
@Service
@Transactional
public class OrderApplicationService implements OrderInputPort {
    
    private final OrderRepository orderRepository;
    private final ProductRepository productRepository;
    private final IdGenerator idGenerator;
    private final EventPublisher eventPublisher;
    
    public OrderApplicationService(
            OrderRepository orderRepository,
            ProductRepository productRepository,
            IdGenerator idGenerator,
            EventPublisher eventPublisher) {
        this.orderRepository = orderRepository;
        this.productRepository = productRepository;
        this.idGenerator = idGenerator;
        this.eventPublisher = eventPublisher;
    }
    
    @Override
    public OrderDTO createOrder(CreateOrderCommand command) {
        // 创建订单
        Order order = Order.create(idGenerator.generateId(), 
            CustomerId.of(command.getCustomerId()));
        
        // 添加商品
        for (OrderItemDTO itemDTO : command.getItems()) {
            Product product = productRepository.findById(
                ProductId.of(itemDTO.getProductId()));
            order.addItem(product, itemDTO.getQuantity());
        }
        
        // 提交订单
        order.submit();
        
        // 保存
        orderRepository.save(order);
        
        // 发布事件
        eventPublisher.publish(new OrderCreatedEvent(order));
        
        return toDTO(order);
    }
}

适配器层:

java 复制代码
// Web适配器(Driving Adapter)
@RestController
public class OrderController implements OrderInputPort {
    
    private final OrderApplicationService orderService;
    
    @PostMapping("/orders")
    public ResponseEntity<OrderDTO> createOrder(@RequestBody CreateOrderRequest request) {
        CreateOrderCommand command = toCommand(request);
        OrderDTO result = orderService.createOrder(command);
        return ResponseEntity.ok(result);
    }
    
    // ... 其他接口方法
}

// JPA适配器(Driven Adapter)
@Repository
public class JpaOrderRepository implements OrderRepository {
    
    @Autowired
    private OrderJpaRepository jpaRepository;
    
    @Override
    public Order findById(OrderId id) {
        return jpaRepository.findById(id.getValue())
            .map(this::toDomain)
            .orElseThrow(() -> new EntityNotFoundException("Order not found"));
    }
    
    @Override
    public Order save(Order order) {
        OrderEntity entity = toEntity(order);
        jpaRepository.save(entity);
        return order;
    }
}

// 消息适配器(Driven Adapter)
@Component
public class KafkaEventPublisher implements EventPublisher {
    
    @Autowired
    private KafkaTemplate<String, Object> kafkaTemplate;
    
    @Override
    public void publish(DomainEvent event) {
        kafkaTemplate.send("domain-events", event.getClass().getSimpleName(), event);
    }
}

// UUID适配器(Driven Adapter)
@Component
public class UuidIdGenerator implements IdGenerator {
    @Override
    public OrderId generateId() {
        return OrderId.of(UUID.randomUUID().toString());
    }
}

三、整洁架构(Clean Architecture)

1. 核心理念

复制代码
整洁架构由Robert C. Martin提出,强调:
- 依赖规则:外层依赖内层,内层不知道外层
- 层次分离:明确的职责边界
- 独立性强:业务逻辑不依赖任何外部框架

2. 架构层次

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                      外层:框架 & 驱动                          │
│    (Web框架、数据库、UI、外部接口、测试框架)                      │
├─────────────────────────────────────────────────────────────────┤
│                      接口适配器层                                │
│    (Controllers、Gateways、Presenters)                          │
├─────────────────────────────────────────────────────────────────┤
│                      应用层                                      │
│    (用例、命令、查询、DTO)                                       │
├─────────────────────────────────────────────────────────────────┤
│                      领域层                                      │
│    (实体、值对象、领域服务、领域事件、接口)                        │
├─────────────────────────────────────────────────────────────────┤
│                      内层:企业业务规则                           │
└─────────────────────────────────────────────────────────────────┘
                          ▲
                          │ 依赖方向
                          │
                          ▼

3. 依赖规则

复制代码
依赖规则(Dependency Rule):
- 源码依赖只能从外向内
- 内层不知道外层的存在
- 外层通过接口依赖内层
- 具体的实现细节放在外层

4. 代码结构

复制代码
com.example.cleanarchitecture
├── domain                         # 领域层(最内层)
│   ├── model
│   │   ├── Order.java
│   │   ├── Product.java
│   │   └── Customer.java
│   ├── service
│   │   └── OrderDomainService.java
│   ├── event
│   │   └── DomainEvent.java
│   └── port                        # 端口(接口)
│       ├── inbound
│       │   ├── CreateOrderUseCase.java
│       │   └── OrderQueryService.java
│       └── outbound
│           ├── OrderRepository.java
│           ├── ProductRepository.java
│           └── EventPublisher.java
├── application                    # 应用层
│   ├── usecase
│   │   ├── CreateOrderUseCaseImpl.java
│   │   └── GetOrderUseCaseImpl.java
│   ├── dto
│   │   ├── CreateOrderCommand.java
│   │   └── OrderDTO.java
│   └── mapper
│       └── OrderMapper.java
├── adapter                        # 适配器层
│   ├── inbound
│   │   ├── web
│   │   │   └── OrderController.java
│   │   └── grpc
│   │       └── OrderGrpcAdapter.java
│   └── outbound
│       ├── persistence
│       │   ├── JpaOrderRepository.java
│       │   └── JpaProductRepository.java
│       ├── messaging
│       │   └── KafkaEventPublisher.java
│       └── external
│           └── PaymentGatewayAdapter.java
└── configuration                  # 配置层
    └── DependencyInjectionConfig.java

5. 整洁架构实现

领域层:

java 复制代码
// 领域实体
public class Order {
    private OrderId id;
    private CustomerId customerId;
    private OrderStatus status;
    private List<OrderItem> items;
    
    public static Order create(OrderId id, CustomerId customerId) {
        return new Order(id, customerId, OrderStatus.DRAFT, new ArrayList<>());
    }
    
    public void addItem(Product product, int quantity) {
        // 业务规则
        if (status != OrderStatus.DRAFT) {
            throw new DomainException("只有草稿订单可以添加商品");
        }
        items.add(new OrderItem(product, quantity));
    }
}

// 输入端口(用例接口)
public interface CreateOrderUseCase {
    OrderDTO execute(CreateOrderCommand command);
}

// 输出端口(仓储接口)
public interface OrderRepository {
    Optional<Order> findById(OrderId id);
    Order save(Order order);
    void delete(OrderId id);
    List<Order> findByCustomerId(CustomerId customerId);
}

应用层:

java 复制代码
// 用例实现
@Service
public class CreateOrderUseCaseImpl implements CreateOrderUseCase {
    
    private final OrderRepository orderRepository;
    private final ProductRepository productRepository;
    private final IdGenerator idGenerator;
    
    public CreateOrderUseCaseImpl(
            OrderRepository orderRepository,
            ProductRepository productRepository,
            IdGenerator idGenerator) {
        this.orderRepository = orderRepository;
        this.productRepository = productRepository;
        this.idGenerator = idGenerator;
    }
    
    @Override
    public OrderDTO execute(CreateOrderCommand command) {
        // 1. 验证客户
        CustomerId customerId = CustomerId.of(command.getCustomerId());
        
        // 2. 创建订单
        OrderId orderId = idGenerator.generateId();
        Order order = Order.create(orderId, customerId);
        
        // 3. 添加商品
        for (OrderItemCommand itemCmd : command.getItems()) {
            Product product = productRepository.findById(ProductId.of(itemCmd.getProductId()))
                .orElseThrow(() -> new DomainException("商品不存在"));
            order.addItem(product, itemCmd.getQuantity());
        }
        
        // 4. 提交订单
        order.submit();
        
        // 5. 保存
        orderRepository.save(order);
        
        // 6. 返回DTO
        return OrderDTO.from(order);
    }
}

适配器层:

java 复制代码
// Web控制器(入站适配器)
@RestController
@RequestMapping("/api/orders")
public class OrderController {
    
    private final CreateOrderUseCase createOrderUseCase;
    private final GetOrderUseCase getOrderUseCase;
    
    @PostMapping
    public ResponseEntity<OrderDTO> createOrder(@RequestBody @Valid CreateOrderRequest request) {
        CreateOrderCommand command = CreateOrderCommand.from(request);
        OrderDTO result = createOrderUseCase.execute(command);
        return ResponseEntity.status(HttpStatus.CREATED).body(result);
    }
    
    @GetMapping("/{id}")
    public ResponseEntity<OrderDTO> getOrder(@PathVariable Long id) {
        OrderDTO result = getOrderUseCase.execute(id);
        return ResponseEntity.ok(result);
    }
}

// JPA仓储(出站适配器)
@Repository
public class JpaOrderRepository implements OrderRepository {
    
    @Autowired
    private OrderJpaRepository jpaRepository;
    
    @Override
    public Optional<Order> findById(OrderId id) {
        return jpaRepository.findById(id.getValue())
            .map(entity -> /* 转换为领域对象 */);
    }
    
    @Override
    public Order save(Order order) {
        OrderEntity entity = toEntity(order);
        jpaRepository.save(entity);
        return order;
    }
}

四、架构对比

1. 六边形 vs 整洁架构

维度 六边形架构 整洁架构
核心理念 端口与适配器 依赖规则
层次划分 端口/适配器/应用/领域 实体/用例/接口适配器/框架
适用场景 轻量级应用 复杂企业应用
学习曲线 较平缓 较陡峭
灵活性 非常高

2. 分层架构对比

维度 传统三层 六边形 整洁架构
可测试性 非常好
可维护性 一般 非常好
耦合度 最低
复杂度

五、实战选择

1. 何时使用六边形

复制代码
适合场景:
- 微服务内部设计
- 需要与多个外部系统交互
- 希望保持业务逻辑的纯粹性
- 团队对DDD有一定了解

2. 何时使用整洁架构

复制代码
适合场景:
- 复杂的企业级应用
- 对可测试性要求极高
- 需要长期维护的项目
- 团队有较强的架构能力

3. 实际项目建议

java 复制代码
// 项目结构建议(根据复杂度选择)

// 简单项目:六边形架构
com.example
├── domain
│   ├── model
│   └── port          # 端口定义
├── application      # 用例
└── adapter          # 适配器

// 复杂项目:整洁架构
com.example
├── domain
│   ├── model
│   ├── service
│   └── port
├── application
│   ├── usecase
│   └── dto
└── adapter
    ├── inbound
    └── outbound

六、测试策略

1. 领域层测试

java 复制代码
// 领域实体测试(无需Spring,纯单元测试)
class OrderTest {
    
    @Test
    void shouldAddItemToDraftOrder() {
        // Given
        Order order = Order.create(OrderId.of("123"), CustomerId.of("456"));
        
        // When
        order.addItem(Product.of("P1", Money.of(100)), 2);
        
        // Then
        assertEquals(1, order.getItems().size());
        assertEquals(Money.of(200), order.getTotalAmount());
    }
    
    @Test
    void shouldRejectAddItemToSubmittedOrder() {
        // Given
        Order order = Order.create(OrderId.of("123"), CustomerId.of("456"));
        order.submit();
        
        // When/Then
        assertThrows(BusinessException.class, 
            () -> order.addItem(Product.of("P1", Money.of(100)), 2));
    }
}

2. 用例层测试

java 复制代码
// 用例测试(使用Mock)
@ExtendWith(MockitoExtension.class)
class CreateOrderUseCaseTest {
    
    @Mock
    private OrderRepository orderRepository;
    
    @Mock
    private ProductRepository productRepository;
    
    @Mock
    private IdGenerator idGenerator;
    
    @InjectMocks
    private CreateOrderUseCaseImpl useCase;
    
    @Test
    void shouldCreateOrderSuccessfully() {
        // Given
        CreateOrderCommand command = CreateOrderCommand.builder()
            .customerId("C123")
            .items(List.of(new OrderItemCommand("P1", 2)))
            .build();
        
        when(productRepository.findById(any())).thenReturn(Optional.of(Product.of("P1", Money.of(100))));
        when(idGenerator.generateId()).thenReturn(OrderId.of("O123"));
        
        // When
        OrderDTO result = useCase.execute(command);
        
        // Then
        assertNotNull(result);
        verify(orderRepository).save(any());
    }
}

七、总结

架构设计的选择建议:

  • 六边形架构:适合微服务、对接多外部系统
  • 整洁架构:适合复杂业务、需要高可测试性
  • 核心原则:业务逻辑与外部依赖解耦

实施建议:

  1. 从六边形架构开始
  2. 随着业务复杂度增加演进到整洁架构
  3. 重视领域模型的设计
  4. 保持架构的持续演进

个人观点,仅供参考

相关推荐
AI服务老曹2 小时前
深度架构解析:如何构建兼容 X86/ARM 及异构计算(GPU/NPU)的级联级 AI 视频管理平台
arm开发·人工智能·架构
企业架构师老王2 小时前
注册审批申报材料自动校验:如何利用实在Agent构建非侵入式架构并降低数据误报率?
大数据·人工智能·ai·架构
踩着两条虫3 小时前
VTJ 平台六大设计模式落地实战指南
开发语言·前端·人工智能·低代码·设计模式·重构·架构
JZC_xiaozhong3 小时前
连锁餐饮企业如何统一ERP、WMS、BOH多系统权限?一套可落地的IAM架构方案
大数据·数据库·架构·iam·企业数据安全·数据集成与应用集成·多系统权限管理
ai产品老杨3 小时前
深度解析:基于异构计算架构的 AI 视频中台(支持 GB28181、RTSP、Docker 部署与源码交付)
人工智能·架构·音视频
Agent手记3 小时前
文献检索智能体:将人工5-8倍提效落地的技术关键是什么?——2026全链路落地实操与核心架构解析
人工智能·ai·架构
James_WangA4 小时前
从 OOM 到矩阵重构:一次 RAG 向量检索引擎的极限优化实录
架构
2603_954708314 小时前
微电网架构优化设计:基于经济性与可靠性的多目标权衡
人工智能·物联网·架构·系统架构·能源
小谢小哥4 小时前
52-熔断降级详解
后端·架构