OrderService_架构设计说明.md 9.7 KB

OrderService 架构设计说明

设计理念

OrderService 采用了统一数据流的设计理念,无论订单数据来源于购物车还是商品规格,最终都会转换为标准化的 goods_list 格式进行处理。这种设计确保了核心业务逻辑的统一性和代码的可维护性。

核心架构

输入层                数据转换层              核心处理层               输出层
┌─────────┐         ┌─────────────┐         ┌─────────────┐         ┌─────────┐
│购物车ID │   ──►   │ 转换为      │   ──►   │             │   ──►   │         │
│cart_ids │         │ goods_list  │         │ 统一计算/   │         │ 订单    │
└─────────┘         └─────────────┘         │ 创建方法    │         │ 结果    │
                                            │             │         │         │
┌─────────┐         ┌─────────────┐         │ calculate   │         └─────────┘
│商品规格 │   ──►   │ 验证格式    │   ──►   │ Order()     │
│goods_list│        │ 直接使用    │         │             │
└─────────┘         └─────────────┘         │ createOrder │
                                            │ ()          │
                                            └─────────────┘

方法层次结构

1. 统一核心方法

calculateOrder() - 统一计算方法

  • 作用: 接收标准化的 goods_list,计算订单明细
  • 输入: 标准化商品列表
  • 输出: 订单计算结果
  • 特点: 所有计算逻辑的统一入口

createOrder() - 统一创建方法

  • 作用: 接收标准化的 goods_list,创建订单
  • 输入: 标准化商品列表
  • 输出: 创建的订单对象
  • 特点: 所有创建逻辑的统一入口

2. 数据转换方法

convertCartToGoodsList() - 购物车转换

  • 作用: 将购物车数据转换为标准商品列表格式
  • 输入: 购物车ID数组
  • 输出: 标准化的 goods_list

3. 对外接口方法

calculateOrderByGoods() - 商品规格计算

public static function calculateOrderByGoods($goods_list, $user_id, $area_id, $user_coupon_id)
{
    return self::calculateOrder($goods_list, $user_id, $area_id, $user_coupon_id);
}

calculateOrderByCart() - 购物车计算

public static function calculateOrderByCart($cart_ids, $user_id, $area_id, $user_coupon_id)
{
    $goods_list = self::convertCartToGoodsList($cart_ids, $user_id);
    return self::calculateOrder($goods_list, $user_id, $area_id, $user_coupon_id);
}

createOrderByGoods() - 商品规格创建

public static function createOrderByGoods($address_id, $user_id, $goods_list, $user_coupon_id, $memo)
{
    return self::createOrder($address_id, $user_id, $goods_list, $user_coupon_id, $memo);
}

createOrderByCart() - 购物车创建

public static function createOrderByCart($address_id, $user_id, $cart_ids, $user_coupon_id, $memo)
{
    $goods_list = self::convertCartToGoodsList($cart_ids, $user_id);
    return self::createOrder($address_id, $user_id, $goods_list, $user_coupon_id, $memo, $cart_ids);
}

标准化数据格式

goods_list 格式

$goods_list = [
    [
        'goods_id' => 1,           // 商品ID(必填)
        'goods_sku_id' => 5,       // 商品规格ID(可选,系统会自动补充默认SKU)
        'nums' => 2                // 购买数量(必填)
    ],
    [
        'goods_id' => 2,
        'goods_sku_id' => 0,       // 可以传0或不传,系统会自动查询默认SKU
        'nums' => 1
    ]
];

重要说明:统一SKU处理机制

在FastAdmin商城系统中,所有商品(包括单规格商品)都会在SKU表中生成记录

  • 单规格商品: 会生成一条默认SKU记录,spec_value_ids为空,is_default=1
  • 多规格商品: 会生成多条SKU记录,其中一条标记为is_default=1

系统处理逻辑

  1. 如果传入goods_sku_id > 0,直接使用指定的SKU
  2. 如果传入goods_sku_id = 0或不传,系统自动查询该商品的默认SKU
  3. 所有商品最终都通过SKU进行价格、库存、规格计算

这种设计确保了:

  • 单规格和多规格商品的处理逻辑完全统一
  • 避免了复杂的条件判断
  • 提供了更好的扩展性和一致性

数据转换示例

购物车数据 → goods_list

// 原始购物车数据
$cartItems = [
    ['id' => 1, 'goods_id' => 1, 'goods_sku_id' => 5, 'nums' => 2],
    ['id' => 2, 'goods_id' => 2, 'goods_sku_id' => 0, 'nums' => 1]
];

// 转换后的 goods_list
$goods_list = [
    ['goods_id' => 1, 'goods_sku_id' => 5, 'nums' => 2],
    ['goods_id' => 2, 'goods_sku_id' => 0, 'nums' => 1]
];

设计优势

1. 代码复用性

  • 单一核心逻辑: 订单计算和创建的核心逻辑只有一份
  • 避免重复代码: 不同数据源最终使用相同的处理逻辑
  • 易于维护: 业务规则变更只需修改核心方法

2. 扩展性

  • 新增数据源: 只需实现数据转换方法
  • 保持接口兼容: 现有的对外接口保持不变
  • 灵活的组合: 可以灵活组合不同的数据源和处理方式

3. 一致性

  • 统一的验证: 所有数据都经过相同的验证流程
  • 统一的错误处理: 错误处理逻辑保持一致
  • 统一的返回格式: 不同接口返回相同格式的数据

4. 性能优化

  • 批量查询优化: 使用 IN 查询替代循环查询,大幅提升性能
  • 减少数据库连接: 统一的查询逻辑减少数据库连接次数
  • 缓存友好: 标准化的数据格式便于缓存
  • 批量处理: 可以更好地支持批量操作

性能优化详解

优化前(循环查询):

foreach ($goods_list as $item) {
    // 每次循环都要查询数据库
    $goods = Goods::where('id', $goods_id)->find();  // N次查询
    $sku = Sku::where('id', $sku_id)->find();        // N次查询
    $sku_attr = Db::name('shop_goods_sku_spec')...   // N次查询
}
// 总计: 3N 次数据库查询

优化后(批量查询):

// 批量查询所有商品
$goodsData = Goods::where('id', 'in', $goods_ids)->select();     // 1次查询

// 批量查询指定的SKU
$skuData = Sku::where('id', 'in', $sku_ids)->select();           // 1次查询

// 批量查询没有指定SKU的商品的默认SKU
$defaultSkuData = Sku::where('goods_id', 'in', $goods_without_sku)
    ->where('is_default', 1)->select();                          // 1次查询

// 批量查询所有规格属性
$skuAttrData = Db::name('shop_goods_sku_spec')...                // 1次查询

foreach ($goods_list as $item) {
    // 直接从内存中获取数据,无需查询数据库
    $goods = $goodsData[$goods_id];
    $sku = $skuData[$sku_id]; // 统一使用SKU数据
}
// 总计: 最多4次数据库查询(固定)

性能提升:

  • 订单包含10个商品时: 30次查询 → 3次查询 (提升90%)
  • 订单包含100个商品时: 300次查询 → 3次查询 (提升99%)

使用场景对比

传统方式(优化前)

// 购物车计算
$cartResult = OrderService::calculateOrderByCart($cart_ids, $user_id, $area_id, $coupon_id);

// 商品规格计算  
$goodsResult = OrderService::calculateOrderByGoods($goods_list, $user_id, $area_id, $coupon_id);

// 两套不同的内部实现逻辑

统一方式(优化后)

// 购物车模式:先转换,再统一计算
$goods_list = OrderService::convertCartToGoodsList($cart_ids, $user_id);
$result = OrderService::calculateOrder($goods_list, $user_id, $area_id, $coupon_id);

// 商品规格模式:直接统一计算
$result = OrderService::calculateOrder($goods_list, $user_id, $area_id, $coupon_id);

// 同一套核心实现逻辑

API控制器层的实现

统一的计算接口

public function calculate()
{
    // 根据类型获取标准化的商品列表
    if ($type === 'cart') {
        $cart_ids = $this->request->post('cart_ids');
        $goods_list = OrderService::convertCartToGoodsList($cart_ids, $this->auth->id);
    } else {
        $goods_list = $this->request->post('goods_list/a');
    }
    
    // 统一调用计算方法
    $result = OrderService::calculateOrder($goods_list, $this->auth->id, $area_id, $user_coupon_id);
}

未来扩展可能

1. 新增数据源

  • 收藏夹批量下单: 实现 convertFavoritesToGoodsList()
  • 推荐商品组合: 实现 convertRecommendToGoodsList()
  • 活动套餐: 实现 convertPackageToGoodsList()

2. 新增处理模式

  • 预约订单: 扩展 calculateOrder() 支持预约模式
  • 分期订单: 扩展计算逻辑支持分期付款
  • 团购订单: 支持团购价格计算

3. 优化方向

  • 异步处理: 大批量商品的异步计算
  • 分布式计算: 支持微服务架构下的订单计算
  • 智能缓存: 基于商品组合的智能缓存策略

总结

这种统一的架构设计通过数据标准化 + 核心逻辑统一的方式,实现了:

  1. 简化了代码结构: 消除了重复的业务逻辑
  2. 提高了代码质量: 统一的验证和错误处理
  3. 增强了可维护性: 核心逻辑修改影响范围明确
  4. 提升了扩展性: 新增功能只需实现数据转换
  5. 保证了一致性: 所有订单操作使用相同的业务规则

这种设计模式体现了软件工程中的单一职责原则开闭原则,是一个优秀的架构设计实践。