Service层主方法业务逻辑过长
当我们的业务逻辑过长是,我们就需要提供子方法,供主方法进行调用。
主方法可以当做一个流程调用,具体的实现逻辑都放在对应的子方法中
在抽象子方法的时候我们通常有以下几种方式:
1.提取私有方法,紧跟住方法后面
当我们的业务逻辑不是很复杂,抽出来的私有子方法不是很多是,就可以放在住方法的后面跟随。
要求子方法数量控制在1~3个最为合适
@Service
public class OrderService {
// 主方法
public OrderResult createOrder(CreateOrderRequest request) {
// 检查库存
checkInventory(request);
// 构建订单
Order order = buildOrder(request, price);
// 保存订单
return saveOrder(order);
}
// 私有方法
private void checkInventory(CreateOrderRequest request) { }
private Order buildOrder(CreateOrderRequest request, BigDecimal price) { }
private OrderResult saveOrder(Order order) { }
}
2.提取Handler类
如果子私有方法过多就不适合跟主方法写在一起了。我们可以选择创建Handler类,用于处理那些可以复用的业务逻辑,然后主方法去调用。
选择Helper类的情况:
- 私有方法过多,4~6个
- 私有方法逻辑相对复杂(每个10+行)
- 功能相对独立(如价格计算、库存检查)
- 可能在其他Service中复用
- 便于单独测试
原来的Service(有点臃肿):
@Service
public class OrderService {
public OrderResult createOrder(CreateOrderRequest request) {
// 校验请求参数
validateOrderRequest(request);
// 计算价格
BigDecimal price = calculateOrderPrice(request);
// 检查库存
checkInventory(request);
// 构建订单
Order order = buildOrder(request, price);
// 保存订单
return saveOrder(order);
}
// 5个私有方法,让Service变得有点长
private void validateOrderRequest(CreateOrderRequest request) { }
private BigDecimal calculateOrderPrice(CreateOrderRequest request) { }
private void checkInventory(CreateOrderRequest request) { }
private Order buildOrder(CreateOrderRequest request, BigDecimal price) { }
private OrderResult saveOrder(Order order) { }
}
重构后(提取Helper类):
提取价格计算Helper:
@Component
public class OrderPriceHelper {
public BigDecimal calculatePrice(CreateOrderRequest request) {
BigDecimal basePrice = getBasePrice(request);
BigDecimal discountPrice = applyDiscount(basePrice, request);
return addTax(discountPrice);
}
private BigDecimal getBasePrice(CreateOrderRequest request) { }
private BigDecimal applyDiscount(BigDecimal basePrice, CreateOrderRequest request) { }
private BigDecimal addTax(BigDecimal price) { }
}
提取库存检查Helper:
@Component
public class OrderInventoryHelper {
public void checkInventory(CreateOrderRequest request) {
for (OrderItem item : request.getItems()) {
validateItemStock(item);
reserveStock(item);
}
}
private void validateItemStock(OrderItem item) { }
private void reserveStock(OrderItem item) { }
}
简化后的Service:
@Service
public class OrderService {
@Resource
private OrderPriceHelper orderPriceHelper;
@Resource
private OrderInventoryHelper orderInventoryHelper;
public OrderResult createOrder(CreateOrderRequest request) {
validateOrderRequest(request);
BigDecimal price = orderPriceHelper.calculatePrice(request);
orderInventoryHelper.checkInventory(request);
Order order = buildOrder(request, price);
return saveOrder(order);
}
// 只保留核心的2个私有方法
private Order buildOrder(CreateOrderRequest request, BigDecimal price) { }
private OrderResult saveOrder(Order order) { }
}
3.提取Processor类
如果主方法的子私有方法超过5~6个,且复用率很低或基本无法复用,就可以创建一个Processor类封装相应业务逻辑。然后service层的业务类调用Processor类的入口即可。
// 订单处理器 - 专门处理订单创建的完整流程
@Component
public class OrderCreationProcessor {
// 处理完整的订单创建流程,只被OrderService使用
public OrderResult process(CreateOrderRequest request) {
// 完整的业务流程:校验 -> 计算 -> 库存 -> 构建 -> 保存 -> 通知
validateRequest(request);
PriceInfo price = calculateTotalPrice(request);
InventoryInfo inventory = reserveInventory(request);
Order order = buildOrder(request, price, inventory);
OrderResult result = saveOrder(order);
sendNotifications(result);
return result;
}
// 大量私有方法,只为这个流程服务
private void validateRequest(...) { /* 20行代码 */ }
private PriceInfo calculateTotalPrice(...) { /* 30行代码 */ }
private InventoryInfo reserveInventory(...) { /* 25行代码 */ }
private Order buildOrder(...) { /* 40行代码 */ }
private OrderResult saveOrder(...) { /* 15行代码 */ }
private void sendNotifications(...) { /* 20行代码 */ }
}
// 只被一个Service使用
@Service
public class OrderService {
@Resource
private OrderCreationProcessor orderProcessor; // 专用
public OrderResult createOrder(CreateOrderRequest request) {
return orderProcessor.process(request);
}
}
4.Handler和Processor类的区别
特征 | Helper类 | Processor类 |
---|---|---|
职责范围 | 辅助功能,工具性质 | 完整业务流程 |
复杂度 | 相对简单,单一职责 | 复杂,多步骤协调 |
复用性 | 高复用,多处调用 | 低复用,专用处理 |
方法数量 | 1-3个公共方法 | 1个主process方法 + 大量私有方法 |
业务 完整性 | 处理业务片段 | 处理完整流程 |
5.Handler类和Utils类的区别
特征 | Helper类 | Utils类 |
---|---|---|
Spring管理 | ✅ @Component,可注入依赖 | ❌ 纯静态类,无Spring依赖 |
方法类型 | 实例方法 | 静态方法 |
依赖注 入 | 可以@Resource其他Bean | 不能注入,无状态 |
业务逻辑 | 可以包含业务逻辑 | 纯工具方法,无业务逻辑 |
数据访问 | 可以访问数据库/调用服务 | 不能访问外部资源 |
🔧 Helper类 - 业务辅助,可注入依赖:
// 业务辅助类,有依赖注入
@Component
public class OrderPriceHelper {
@Resource
private DiscountService discountService; // 需要注入其他服务
@Resource
private TaxConfigRepository taxConfigRepository; // 需要访问数据库
// 实例方法,包含业务逻辑
public BigDecimal calculatePrice(List<OrderItem> items, Long userId) {
BigDecimal basePrice = calculateBasePrice(items);
// 调用其他服务获取用户折扣 - 业务逻辑
DiscountInfo discount = discountService.getUserDiscount(userId);
BigDecimal discountedPrice = applyDiscount(basePrice, discount);
// 访问数据库获取税率配置 - 业务逻辑
TaxConfig taxConfig = taxConfigRepository.findByRegion("CN");
return addTax(discountedPrice, taxConfig.getRate());
}
private BigDecimal calculateBasePrice(List<OrderItem> items) { }
private BigDecimal applyDiscount(BigDecimal price, DiscountInfo discount) { }
private BigDecimal addTax(BigDecimal price, BigDecimal taxRate) { }
}
// 使用方式:需要注入
@Service
public class OrderService {
@Resource
private OrderPriceHelper orderPriceHelper; // 注入使用
public OrderResult createOrder(CreateOrderRequest request) {
BigDecimal price = orderPriceHelper.calculatePrice(request.getItems(), request.getUserId());
}
}
🛠️ Utils类 - 纯工具,静态方法:
// 纯工具类,无业务逻辑
public class DateUtils {
// 静态方法,无依赖
public static String formatDate(Date date, String pattern) {
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
return sdf.format(date);
}
public static Date parseDate(String dateStr, String pattern) {
// 纯字符串转换,无业务逻辑
}
public static boolean isWeekend(Date date) {
// 纯计算逻辑
}
}
public class StringUtils {
public static boolean isEmpty(String str) {
return str == null || str.trim().isEmpty();
}
public static String camelToSnake(String camelCase) {
// 纯字符串转换
}
}
// 使用方式:直接静态调用
String formatted = DateUtils.formatDate(new Date(), "yyyy-MM-dd");