灾害去除系统优化说明.md 7.5 KB

灾害去除系统优化说明

优化背景

原有的灾害去除系统存在以下问题:

  1. 概率属性未使用:虽然获取了物品的概率属性,但没有实际使用它进行成功率判断
  2. 魔法数字问题:代码中直接使用数字(1、2、3)表示灾害类型,缺乏可读性
  3. 缺少事务处理:Handler层没有开启事务,但逻辑层要求外部开启事务
  4. 代码重复:三个灾害去除Handler(除虫、除草、浇水)有大量重复代码
  5. 属性名称不一致:物品属性命名不规范,缺少部分属性定义

优化内容

1. 物品属性完善

修正属性命名

  • 修正前fram_grass_rate(草宰概率)
  • 修正后fram_weedicide_rate(除草概率)

完善属性定义

NumericAttributesCast 中添加了完整的灾害去除属性:

/**
 * 除虫概率(百分比格式,100=100%)
 */
public int $fram_pesticide_rate = 0;

/**
 * 解决干旱概率(百分比格式,100=100%)
 */
public int $fram_drought_rate = 0;

/**
 * 除草概率(百分比格式,100=100%)
 */
public int $fram_weedicide_rate = 0;

2. 创建验证层架构

新增 DisasterRemovalValidation 类

位置:app/Module/Farm/Validations/DisasterRemovalValidation.php

核心功能

  • 统一的数据验证规则定义
  • 集成自定义验证器
  • 符合框架的验证架构设计

新增 LandOwnershipValidator 类

位置:app/Module/Farm/Validators/LandOwnershipValidator.php

核心功能

  • 验证土地是否属于指定用户
  • 使用addError方法进行错误处理
  • 支持参数化配置

新增 DisasterRemovalItemValidator 类

位置:app/Module/Farm/Validators/DisasterRemovalItemValidator.php

核心功能

  • 验证用户是否拥有指定物品
  • 验证物品是否具有对应的灾害去除属性
  • 支持多种灾害类型的验证

3. 创建统一的灾害去除逻辑

新增 DisasterRemovalLogic 类

位置:app/Module/Farm/Logics/DisasterRemovalLogic.php

核心功能

  • 统一的概率计算和判断逻辑
  • 事务状态检查(使用 Helper::check_tr()
  • 灾害类型与物品属性的映射管理
  • 完整的错误处理和日志记录

关键特性

  • 概率判断:使用物品的概率属性进行成功率计算
  • 失败处理:即使失败也会消耗物品,符合游戏逻辑
  • 类型安全:使用枚举替代魔法数字
  • 事务要求:要求调用者开启事务,符合架构设计
  • 专注业务逻辑:不再包含验证逻辑,假设所有验证已通过

3. 服务层扩展

CropService 新增方法

/**
 * 使用物品去除灾害(带概率判断)
 */
public static function removeDisasterWithItem(
    int $userId,
    int $landId,
    int $itemId,
    int $disasterType,
    string $sourceType
): array

5. Handler层重构

验证前置的处理模式

所有灾害去除Handler(PesticideHandler、WeedicideHandler、WateringHandler)都采用相同的处理模式:

// 先进行验证,避免不必要的事务开销
$validation = new \App\Module\Farm\Validations\DisasterRemovalValidation([
    'user_id' => $userId,
    'land_id' => $landId,
    'item_id' => $userItemId,
    'disaster_type' => DISASTER_TYPE::PEST->value
]);

// 验证数据
$validation->validated();

// 验证通过后,开启事务
DB::beginTransaction();

// 执行业务逻辑(不再需要验证)
$result = CropService::removeDisasterWithItem(
    $userId,
    $landId,
    $userItemId,
    DISASTER_TYPE::PEST->value,  // 使用枚举替代魔法数字
    'land_pesticide'
);

// 提交事务
DB::commit();

分层异常处理

} catch (\UCore\Exception\ValidateException $e) {
    // 验证失败,此时可能还没有开启事务
    $this->response->setCode(400);
    $this->response->setMsg($e->getMessage());
} catch (LogicException $e) {
    // 业务逻辑异常,需要回滚事务
    if (DB::transactionLevel() > 0) {
        DB::rollBack();
    }
} catch (\Exception $e) {
    // 系统异常,需要回滚事务
    if (DB::transactionLevel() > 0) {
        DB::rollBack();
    }
}

消除魔法数字

  • 修正前CropService::clearDisaster($userId, $landId, 2)
  • 修正后DISASTER_TYPE::PEST->value

5. 概率计算逻辑

概率判断算法

private function rollSuccess(int $successRate): bool
{
    if ($successRate <= 0) {
        return false;  // 0%成功率必定失败
    }

    if ($successRate >= 100) {
        return true;   // 100%成功率必定成功
    }

    $randomNumber = mt_rand(1, 100);
    return $randomNumber <= $successRate;
}

失败时的处理

  • 即使操作失败,仍然会消耗物品
  • 返回明确的失败信息,提示用户重试
  • 记录详细的操作日志

灾害类型映射

灾害类型与物品属性映射

private const DISASTER_ITEM_ATTRIBUTES = [
    DISASTER_TYPE::DROUGHT->value => 'fram_drought_rate',    // 干旱 -> 浇水概率
    DISASTER_TYPE::PEST->value => 'fram_pesticide_rate',     // 虫害 -> 除虫概率
    DISASTER_TYPE::WEED->value => 'fram_weedicide_rate',     // 杂草 -> 除草概率
];

灾害类型与操作名称映射

private const DISASTER_ACTION_NAMES = [
    DISASTER_TYPE::DROUGHT->value => '浇水',
    DISASTER_TYPE::PEST->value => '除虫',
    DISASTER_TYPE::WEED->value => '除草',
];

事务处理优化

事务管理策略

  1. Handler层负责:开启和提交/回滚事务
  2. 逻辑层检查:使用 Helper::check_tr() 确保事务已开启
  3. 异常处理:任何异常都会触发事务回滚

事务检查机制

// 在逻辑层开始时检查事务状态
Helper::check_tr();

错误处理改进

详细的日志记录

  • 成功操作:记录用户ID、土地ID、物品ID、灾害类型、成功率
  • 失败操作:记录错误原因、堆栈跟踪、相关参数
  • 异常处理:区分业务异常和系统异常

用户友好的错误信息

  • 明确的失败原因提示
  • 针对不同灾害类型的个性化消息
  • 引导用户进行正确操作

兼容性说明

向后兼容

  • 保留原有的 CropService::clearDisaster() 方法
  • 新增的方法不影响现有功能
  • 数据库结构无变化

API兼容

  • Handler的请求和响应格式保持不变
  • 只是内部实现逻辑的优化
  • 客户端无需修改

使用示例

物品配置示例

{
  "numeric_attributes": {
    "fram_pesticide_rate": 80,    // 80%除虫成功率
    "fram_drought_rate": 90,      // 90%解决干旱成功率
    "fram_weedicide_rate": 75     // 75%除草成功率
  }
}

调用示例

// 使用除虫剂
$result = CropService::removeDisasterWithItem(
    $userId,
    $landId,
    $pesticideItemId,
    DISASTER_TYPE::PEST->value,
    'land_pesticide'
);

if ($result['success']) {
    echo $result['message'];  // "除虫成功"
    echo "成功率: " . $result['success_rate'] . "%";
}

性能优化

减少重复代码

  • 三个Handler的代码量减少约60%
  • 统一的逻辑处理,便于维护和扩展

优化查询

  • 减少重复的验证查询
  • 统一的物品验证逻辑

扩展性

新增灾害类型

只需在以下位置添加配置:

  1. DISASTER_TYPE 枚举
  2. DISASTER_ITEM_ATTRIBUTES 映射
  3. DISASTER_ACTION_NAMES 映射
  4. NumericAttributesCast 属性定义

新增去除道具

只需在物品的 numeric_attributes 中添加对应的概率属性即可。