Service子私有方法过多导致屎山的解决思路

0 阅读4分钟

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");