外卖CPS系统长期迭代技巧:Java后端通过合理包结构设计避免业务代码变成屎山

外卖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包中。当需要修改分润规则或订单状态流转时,开发者可以迅速定位到相关代码,而不会牵一发而动全身。这种高内聚、低耦合的设计是系统能够长期健康迭代的关键。

本文著作权归 俱美开放平台 ,转载请注明出处!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值