分层架构详解
分层架构详解
分层架构的基本概念
分层架构是一种将软件系统划分为多个水平层的架构模式,每层只与相邻层交互。这种模式通过关注点分离来降低系统复杂性,提高可维护性和可测试性。
经典分层模型
四层架构
最常见的分层架构包含四个层次:
┌─────────────────────────┐
│ 表示层 (UI) │ 用户界面、用户交互
├─────────────────────────┤
│ 业务逻辑层 (BLL) │ 业务规则、流程处理
├─────────────────────────┤
│ 数据访问层 (DAL) │ 数据持久化、ORM
├─────────────────────────┤
│ 数据库层 (DB) │ 数据存储
└─────────────────────────┘
五层架构
在某些场景下,会在业务逻辑层和数据访问层之间增加一个服务层:
┌─────────────────────────┐
│ 表示层 (UI) │
├─────────────────────────┤
│ 业务逻辑层 (BLL) │
├─────────────────────────┤
│ 服务层 (Service) │ 领域服务、用例编排
├─────────────────────────┤
│ 数据访问层 (DAL) │
├─────────────────────────┤
│ 数据库层 (DB) │
└─────────────────────────┘
各层职责详解
表示层
表示层负责处理用户界面和用户交互,不包含任何业务逻辑。
// 表示层 - REST Controller
@RestController
@RequestMapping("/api/v1/orders")
public class OrderController {
private final OrderFacade orderFacade;
public OrderController(OrderFacade orderFacade) {
this.orderFacade = orderFacade;
}
@GetMapping("/{id}")
public ResponseEntity<OrderDto> getOrder(@PathVariable Long id) {
OrderDto order = orderFacade.getOrder(id);
return ResponseEntity.ok(order);
}
@PostMapping
public ResponseEntity<OrderDto> createOrder(@RequestBody CreateOrderRequest request) {
OrderDto order = orderFacade.createOrder(request);
return ResponseEntity.status(HttpStatus.CREATED).body(order);
}
@PutMapping("/{id}/status")
public ResponseEntity<Void> updateOrderStatus(
@PathVariable Long id,
@RequestBody UpdateStatusRequest request) {
orderFacade.updateOrderStatus(id, request.getStatus());
return ResponseEntity.ok().build();
}
}
业务逻辑层
业务逻辑层包含核心业务规则和流程,是系统最重要的层次。
// 业务逻辑层 - 领域服务
@Service
@Transactional
public class OrderDomainService {
private final OrderRepository orderRepository;
private final InventoryService inventoryService;
private final PricingService pricingService;
public OrderDomainService(
OrderRepository orderRepository,
InventoryService inventoryService,
PricingService pricingService) {
this.orderRepository = orderRepository;
this.inventoryService = inventoryService;
this.pricingService = pricingService;
}
public Order createOrder(CreateOrderCommand command) {
// 业务规则验证
validateOrder(command);
// 创建订单聚合根
Order order = OrderFactory.create(command);
// 应用业务规则
order.applyPricing(pricingService.calculatePrice(order));
order.reserveInventory(inventoryService);
// 持久化
return orderRepository.save(order);
}
private void validateOrder(CreateOrderCommand command) {
if (command.getItems() == null || command.getItems().isEmpty()) {
throw new InvalidOrderException("Order must contain at least one item");
}
for (OrderItem item : command.getItems()) {
if (item.getQuantity() <= 0) {
throw new InvalidOrderException("Invalid quantity for item: " + item.getProductId());
}
}
}
}
数据访问层
数据访问层负责与数据存储交互,隐藏数据持久化的细节。
// 数据访问层 - Repository
@Repository
public class JpaOrderRepository implements OrderRepository {
private final OrderJpaRepository jpaRepository;
private final OrderMapper mapper;
public JpaOrderRepository(OrderJpaRepository jpaRepository, OrderMapper mapper) {
this.jpaRepository = jpaRepository;
this.mapper = mapper;
}
@Override
public Order save(Order order) {
OrderJpaEntity entity = mapper.toJpaEntity(order);
OrderJpaEntity savedEntity = jpaRepository.save(entity);
return mapper.toDomainEntity(savedEntity);
}
@Override
public Optional<Order> findById(Long id) {
return jpaRepository.findById(id)
.map(mapper::toDomainEntity);
}
@Override
public List<Order> findByCustomerId(Long customerId) {
return jpaRepository.findByCustomerId(customerId)
.stream()
.map(mapper::toDomainEntity)
.collect(Collectors.toList());
}
}
// JPA实体
@Entity
@Table(name = "orders")
public class OrderJpaEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "customer_id")
private Long customerId;
@Enumerated(EnumType.STRING)
private OrderStatus status;
@Column(name = "total_amount")
private BigDecimal totalAmount;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "order_id")
private List<OrderItemJpaEntity> items;
// getters and setters
}
层间通信机制
依赖方向
分层架构的一个关键原则是依赖方向:上层依赖下层,下层不知道上层的存在。
表示层 → 业务逻辑层 → 数据访问层 → 数据库层
DTO(数据传输对象)
DTO用于在层间传输数据,避免直接暴露领域模型或数据库实体。
// DTO定义
public class OrderDto {
private Long id;
private Long customerId;
private String status;
private BigDecimal totalAmount;
private List<OrderItemDto> items;
private LocalDateTime createdAt;
}
public class OrderItemDto {
private Long productId;
private String productName;
private Integer quantity;
private BigDecimal unitPrice;
private BigDecimal totalPrice;
}
// 请求DTO
public class CreateOrderRequest {
private Long customerId;
private List<CreateOrderItemRequest> items;
}
// 响应DTO
public class OrderResponse {
private OrderDto order;
private String message;
}
Facade模式
Facade模式为复杂子系统提供一个简单的接口,简化表示层的调用。
// Facade实现
@Service
public class OrderFacade {
private final OrderDomainService orderDomainService;
private final OrderQueryService orderQueryService;
private final OrderMapper orderMapper;
public OrderDto getOrder(Long id) {
Order order = orderQueryService.findById(id);
return orderMapper.toDto(order);
}
public OrderDto createOrder(CreateOrderRequest request) {
CreateOrderCommand command = orderMapper.toCommand(request);
Order order = orderDomainService.createOrder(command);
return orderMapper.toDto(order);
}
public void updateOrderStatus(Long id, String status) {
OrderStatus orderStatus = OrderStatus.valueOf(status);
orderDomainService.updateOrderStatus(id, orderStatus);
}
}
分层架构的优缺点
优点
- 关注点分离:每层只关注特定职责
- 易于理解:层次结构清晰,便于新成员理解
- 可测试性:可以独立测试每一层
- 可替换性:可以替换某一层的实现而不影响其他层
缺点
- 性能开销:层间通信增加性能开销
- 级联修改:修改可能需要跨多层
- 过度工程:简单项目可能不需要完整的分层
- 数据传输开销:DTO转换增加代码量
最佳实践
- 严格遵循依赖方向:上层依赖下层,禁止反向依赖
- 使用DTO传输数据:避免直接暴露领域模型
- 保持层的独立性:每层应该可以独立测试和替换
- 合理划分层次:根据项目复杂度决定层次数量
- 文档化层间接口:清晰定义每层的职责和接口