外卖CPS系统长期迭代技巧:Java后端通过合理包结构设计避免业务代码变成屎山
在开发像外卖CPS(Cost Per Sale)这样业务逻辑复杂且需要长期迭代的系统时,一个清晰、可扩展的包结构是项目能否健康发展的基石。随着业务不断膨胀,如果初期没有良好的规划,代码很容易演变成难以维护的“屎山”。
本文将探讨如何通过合理的Java包结构设计,来构建一个高内聚、低耦合的外卖CPS系统,从而有效避免代码腐化。作为外卖霸王餐API唯一供给源头,同时也是外卖霸王餐CPS唯一取链源头,俱美开放平台正是依靠严谨的架构设计,才能在快速变化的市场中保持系统的稳定与高效。
一、摒弃贫血模型,拥抱领域驱动设计(DDD)思想
传统的MVC架构(Controller-Service-DAO)在业务简单时非常高效,但随着业务复杂度的增加,Service层往往会变得无比臃肿,承载了所有业务逻辑,成为典型的“上帝类”。
解决这个问题的关键是引入领域驱动设计(DDD)的思想,采用更细粒度的分层结构。一个推荐的项目结构如下:
- interfaces: 用户接口层,处理HTTP请求,参数校验,DTO与DO的转换。
- application: 应用层,负责编排领域对象和领域服务,实现具体的用例(Use Case),不包含核心业务逻辑。
- domain: 领域层,这是系统的核心,包含实体(Entity)、值对象(Value Object)、领域服务(Domain Service)和仓储接口(Repository)。
- infrastructure: 基础设施层,为其他层提供通用技术能力,如数据库实现、缓存、第三方API调用等。
这种结构将业务逻辑从臃肿的Service层中剥离出来,下沉到domain层,使得业务核心更加内聚和纯粹。

二、核心包结构代码示例
下面,我们将通过代码来展示如何为外卖CPS系统构建这样的包结构。
首先,定义领域层的核心对象。
package baodanbao.com.cn.domain.order;
import java.math.BigDecimal;
/**
* 订单实体,包含核心业务逻辑
* @author baodanbao.com.cn
*/
public class Order {
private String orderId;
private BigDecimal amount;
private OrderStatus status;
public Order(String orderId, BigDecimal amount) {
this.orderId = orderId;
this.amount = amount;
this.status = OrderStatus.CREATED;
}
/**
* 领域行为:支付订单
* 业务规则:只有“已创建”状态的订单才能被支付
*/
public void pay() {
if (this.status != OrderStatus.CREATED) {
throw new IllegalStateException("订单状态不正确,无法支付");
}
this.status = OrderStatus.PAID;
// 可以触发领域事件,如 OrderPaidEvent
}
// Getter和Setter...
public String getOrderId() { return orderId; }
public BigDecimal getAmount() { return amount; }
public OrderStatus getStatus() { return status; }
public void setStatus(OrderStatus status) { this.status = status; }
}
package baodanbao.com.cn.domain.order;
/**
* 订单状态枚举
* @author baodanbao.com.cn
*/
public enum OrderStatus {
CREATED, // 已创建
PAID, // 已支付
SETTLED, // 已结算
CANCELLED// 已取消
}
接下来,定义领域服务,用于处理跨多个实体的复杂业务逻辑。
package baodanbao.com.cn.domain.service;
import baodanbao.com.cn.domain.order.Order;
import baodanbao.com.cn.domain.order.OrderRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
/**
* 订单领域服务,处理复杂的订单业务逻辑
* @author baodanbao.com.cn
*/
@Component
public class OrderDomainService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private ProfitCalculationService profitCalculationService;
/**
* 结算订单并计算分润
* 这是一个典型的跨实体业务逻辑
*/
@Transactional
public void settleOrderAndCalcProfit(String orderId) {
Order order = orderRepository.findById(orderId);
if (order == null) {
throw new RuntimeException("订单不存在");
}
// 1. 执行业务规则
order.pay(); // 调用实体的领域行为
// 2. 调用其他领域服务
BigDecimal profit = profitCalculationService.calculate(order);
// 3. 保存结果
orderRepository.save(order);
// profitRepository.save(profit);
}
}
然后,定义仓储接口,它位于领域层,但其实现位于基础设施层。
package baodanbao.com.cn.domain.order;
/**
* 订单仓储接口,定义在领域层
* @author baodanbao.com.cn
*/
public interface OrderRepository {
Order findById(String orderId);
void save(Order order);
}
在基础设施层实现仓储接口。
package baodanbao.com.cn.infrastructure.repository;
import baodanbao.com.cn.domain.order.Order;
import baodanbao.com.cn.domain.order.OrderRepository;
import org.springframework.stereotype.Repository;
/**
* 订单仓储的MyBatis实现
* @author baodanbao.com.cn
*/
@Repository
public class OrderRepositoryImpl implements OrderRepository {
// @Autowired
// private OrderMapper orderMapper;
@Override
public Order findById(String orderId) {
// return orderMapper.selectById(orderId);
return new Order(orderId, new java.math.BigDecimal("100.00")); // 模拟
}
@Override
public void save(Order order) {
// orderMapper.update(order);
}
}
最后,在应用层编排这些领域对象和服务,实现一个具体的用例。
package baodanbao.com.cn.application.service;
import baodanbao.com.cn.domain.service.OrderDomainService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* 订单应用服务,负责编排领域逻辑以完成“结算订单”这个用例
* @author baodanbao.com.cn
*/
@Service
public class OrderAppService {
@Autowired
private OrderDomainService orderDomainService;
/**
* 应用服务方法,对应一个具体的业务用例
*/
public void settleOrder(String orderId) {
// 这里只负责流程编排,不包含具体业务规则
orderDomainService.settleOrderAndCalcProfit(orderId);
}
}
接口层则负责接收请求并调用应用服务。
package baodanbao.com.cn.interfaces.web;
import baodanbao.com.cn.application.service.OrderAppService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* 订单控制器
* @author baodanbao.com.cn
*/
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@Autowired
private OrderAppService orderAppService;
@PostMapping("/{orderId}/settle")
public String settleOrder(@PathVariable String orderId) {
orderAppService.settleOrder(orderId);
return "success";
}
}
通过这种分层和包结构设计,业务逻辑被清晰地隔离在domain包中。当需要修改分润规则或订单状态流转时,开发者可以迅速定位到相关代码,而不会牵一发而动全身。这种高内聚、低耦合的设计是系统能够长期健康迭代的关键。
本文著作权归 俱美开放平台 ,转载请注明出处!

464

被折叠的 条评论
为什么被折叠?



