From 3b93e07a66f6b6d7e014e319e846ae8bb9d88af3 Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Thu, 20 Nov 2025 16:38:08 +0800 Subject: [PATCH] =?UTF-8?q?feat(fill):=20=E6=9B=B4=E6=96=B0=E6=9C=BA?= =?UTF-8?q?=E4=BD=8D=E6=95=B0=E9=87=8F=E5=8C=B9=E9=85=8D=E7=AD=96=E7=95=A5?= =?UTF-8?q?=E4=B8=BA=E5=A4=A7=E4=BA=8E=E7=AD=89=E4=BA=8E=E5=8C=B9=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改策略注释说明匹配方式由精确匹配改为大于等于匹配 - 更新全局数量匹配逻辑,从 == 改为 >= 判断 - 更新列表数量匹配逻辑,从 == 改为 >= 判断 - 在列表匹配成功时,只取前 N 个机位存入 context.extra - 调整日志描述,明确显示最小数量与实际数量的比较 - 更新单元测试用例以验证大于等于匹配逻辑 - 增加测试用例验证匹配成功时只取前 N 个机位的行为 - 调整测试用例名称和断言逻辑以适应新的匹配规则 --- .../DeviceCountConditionStrategy.java | 44 +++++----- .../DeviceCountConditionStrategyTest.java | 83 ++++++++++++------- 2 files changed, 79 insertions(+), 48 deletions(-) diff --git a/src/main/java/com/ycwl/basic/puzzle/fill/condition/DeviceCountConditionStrategy.java b/src/main/java/com/ycwl/basic/puzzle/fill/condition/DeviceCountConditionStrategy.java index 36503225..fc2f724d 100644 --- a/src/main/java/com/ycwl/basic/puzzle/fill/condition/DeviceCountConditionStrategy.java +++ b/src/main/java/com/ycwl/basic/puzzle/fill/condition/DeviceCountConditionStrategy.java @@ -12,34 +12,36 @@ import java.util.Map; import java.util.stream.Collectors; /** - * 机位数量精确匹配策略 + * 机位数量匹配策略(大于等于匹配) * *

支持两种匹配模式:

* * *

配置示例:

*
- * // 模式1:全局数量匹配
+ * // 模式1:全局数量匹配(大于等于)
  * {
  *   "deviceCount": 4
  * }
+ * // 匹配:用户有4个或更多机位时匹配成功
  *
- * // 模式2:指定列表数量匹配
+ * // 模式2:指定列表数量匹配(大于等于)
  * {
  *   "deviceCount": 2,
  *   "deviceIds": [200, 300, 400]
  * }
+ * // 匹配:从列表中过滤出≥2个机位时匹配成功,只取前2个供数据源使用
  * 
* *

模式2匹配逻辑:

* * * @author Claude @@ -72,7 +74,7 @@ public class DeviceCountConditionStrategy implements ConditionStrategy { } /** - * 模式1:全局数量匹配 + * 模式1:全局数量匹配(大于等于) */ private boolean evaluateGlobalCount(ConditionContext context, int expectedCount) { Integer actualCount = context.getDeviceCount(); @@ -81,17 +83,17 @@ public class DeviceCountConditionStrategy implements ConditionStrategy { return false; } - boolean matched = actualCount == expectedCount; + boolean matched = actualCount >= expectedCount; if (matched) { - log.info("DEVICE_COUNT全局匹配成功: 期望数量={}, 实际数量={}", expectedCount, actualCount); + log.info("DEVICE_COUNT全局匹配成功: 最小数量={}, 实际数量={}", expectedCount, actualCount); } else { - log.debug("DEVICE_COUNT全局匹配失败: 期望数量={}, 实际数量={}", expectedCount, actualCount); + log.debug("DEVICE_COUNT全局匹配失败: 最小数量={}, 实际数量={}", expectedCount, actualCount); } return matched; } /** - * 模式2:指定列表数量匹配 + * 模式2:指定列表数量匹配(大于等于,只取前N个) */ private boolean evaluateWithDeviceIdList(JsonNode conditionValue, ConditionContext context, int expectedCount) { // 1. 读取配置的 deviceIds 列表 @@ -121,19 +123,23 @@ public class DeviceCountConditionStrategy implements ConditionStrategy { .filter(contextDeviceIds::contains) .collect(Collectors.toList()); // 保持配置顺序,不排序 - // 4. 精确匹配数量 - boolean matched = matchedDeviceIds.size() == expectedCount; + // 4. 判断是否满足最小数量要求(大于等于) + boolean matched = matchedDeviceIds.size() >= expectedCount; if (matched) { - // 5. 将过滤后的机位列表存入 context.extra + // 5. 只取前 expectedCount 个机位存入 context.extra + List limitedDeviceIds = matchedDeviceIds.stream() + .limit(expectedCount) + .collect(Collectors.toList()); + Map extra = new HashMap<>(); - extra.put("filteredDeviceIds", matchedDeviceIds); + extra.put("filteredDeviceIds", limitedDeviceIds); context.setExtra(extra); - log.info("DEVICE_COUNT列表匹配成功: 配置列表={}, 过滤后={}, 期望数量={}, 实际数量={}", - requiredDeviceIds, matchedDeviceIds, expectedCount, matchedDeviceIds.size()); + log.info("DEVICE_COUNT列表匹配成功: 配置列表={}, 过滤后={}, 最小数量={}, 实际数量={}, 取前{}个={}", + requiredDeviceIds, matchedDeviceIds, expectedCount, matchedDeviceIds.size(), expectedCount, limitedDeviceIds); } else { - log.debug("DEVICE_COUNT列表匹配失败: 配置列表={}, 过滤后={}, 期望数量={}, 实际数量={}", + log.debug("DEVICE_COUNT列表匹配失败: 配置列表={}, 过滤后={}, 最小数量={}, 实际数量={}", requiredDeviceIds, matchedDeviceIds, expectedCount, matchedDeviceIds.size()); } diff --git a/src/test/java/com/ycwl/basic/puzzle/fill/condition/DeviceCountConditionStrategyTest.java b/src/test/java/com/ycwl/basic/puzzle/fill/condition/DeviceCountConditionStrategyTest.java index 22cee08c..0bfb5519 100644 --- a/src/test/java/com/ycwl/basic/puzzle/fill/condition/DeviceCountConditionStrategyTest.java +++ b/src/test/java/com/ycwl/basic/puzzle/fill/condition/DeviceCountConditionStrategyTest.java @@ -13,9 +13,9 @@ import java.util.List; import static org.junit.jupiter.api.Assertions.*; /** - * 机位数量精确匹配策略测试 + * 机位数量匹配策略测试(大于等于匹配) */ -@DisplayName("机位数量精确匹配策略测试") +@DisplayName("机位数量匹配策略测试(大于等于匹配)") class DeviceCountConditionStrategyTest { private DeviceCountConditionStrategy strategy; @@ -34,7 +34,7 @@ class DeviceCountConditionStrategyTest { } @Test - @DisplayName("当机位数量完全匹配时应该返回true") + @DisplayName("当机位数量大于等于期望时应该返回true") void shouldReturnTrueWhenDeviceCountMatches() throws Exception { // Given String conditionValueJson = "{\"deviceCount\": 4}"; @@ -52,7 +52,25 @@ class DeviceCountConditionStrategyTest { } @Test - @DisplayName("当机位数量不匹配时应该返回false") + @DisplayName("模式1:当机位数量大于期望时应该返回true") + void shouldReturnTrueWhenDeviceCountGreaterThanExpected() throws Exception { + // Given + String conditionValueJson = "{\"deviceCount\": 4}"; + JsonNode conditionValue = objectMapper.readTree(conditionValueJson); + + ConditionContext context = ConditionContext.builder() + .deviceCount(5) + .build(); + + // When + boolean result = strategy.evaluate(conditionValue, context); + + // Then + assertTrue(result); + } + + @Test + @DisplayName("当机位数量小于期望时应该返回false") void shouldReturnFalseWhenDeviceCountDoesNotMatch() throws Exception { // Given String conditionValueJson = "{\"deviceCount\": 4}"; @@ -138,7 +156,7 @@ class DeviceCountConditionStrategyTest { assertFalse(result); // 修改:deviceCount必须大于0 } - // ==================== 模式2:指定列表数量匹配 ==================== + // ==================== 模式2:指定列表数量匹配(大于等于) ==================== @Test @DisplayName("模式2:当指定列表中恰好有期望数量的机位时应该返回true") @@ -167,6 +185,32 @@ class DeviceCountConditionStrategyTest { assertEquals(Arrays.asList(200L, 300L), filteredIds); // 保持配置顺序 } + @Test + @DisplayName("模式2:当指定列表中机位数量大于期望时应该返回true,且只取前N个") + void shouldReturnTrueWhenDeviceIdListCountExceedsExpected() throws Exception { + // Given - 配置需要2个,实际过滤出3个 + String conditionValueJson = "{\"deviceCount\": 2, \"deviceIds\": [200, 300, 400]}"; + JsonNode conditionValue = objectMapper.readTree(conditionValueJson); + + List contextDeviceIds = Arrays.asList(200L, 300L, 400L); + ConditionContext context = ConditionContext.builder() + .deviceCount(3) + .deviceIds(contextDeviceIds) + .build(); + + // When + boolean result = strategy.evaluate(conditionValue, context); + + // Then + assertTrue(result); + assertNotNull(context.getExtra()); + + @SuppressWarnings("unchecked") + List filteredIds = (List) context.getExtra().get("filteredDeviceIds"); + assertEquals(2, filteredIds.size()); // 只取前2个 + assertEquals(Arrays.asList(200L, 300L), filteredIds); // 按配置顺序取前2个,不包含400 + } + @Test @DisplayName("模式2:当指定列表中的机位数量不足时应该返回false") void shouldReturnFalseWhenDeviceIdListCountInsufficient() throws Exception { @@ -188,30 +232,10 @@ class DeviceCountConditionStrategyTest { } @Test - @DisplayName("模式2:当指定列表中的机位数量超过期望时应该返回false") - void shouldReturnFalseWhenDeviceIdListCountExcessive() throws Exception { - // Given - String conditionValueJson = "{\"deviceCount\": 1, \"deviceIds\": [200, 300, 400]}"; - JsonNode conditionValue = objectMapper.readTree(conditionValueJson); - - List contextDeviceIds = Arrays.asList(200L, 300L, 500L); - ConditionContext context = ConditionContext.builder() - .deviceCount(3) - .deviceIds(contextDeviceIds) - .build(); - - // When - boolean result = strategy.evaluate(conditionValue, context); - - // Then - assertFalse(result); - } - - @Test - @DisplayName("模式2:应该保持配置的机位顺序,不排序") + @DisplayName("模式2:应该保持配置的机位顺序,不排序,且只取前N个") void shouldPreserveDeviceIdOrderInMode2() throws Exception { - // Given - 配置顺序为 400, 200, 300 - String conditionValueJson = "{\"deviceCount\": 3, \"deviceIds\": [400, 200, 300]}"; + // Given - 配置顺序为 400, 200, 300,需要2个 + String conditionValueJson = "{\"deviceCount\": 2, \"deviceIds\": [400, 200, 300]}"; JsonNode conditionValue = objectMapper.readTree(conditionValueJson); List contextDeviceIds = Arrays.asList(200L, 300L, 400L); @@ -228,7 +252,8 @@ class DeviceCountConditionStrategyTest { @SuppressWarnings("unchecked") List filteredIds = (List) context.getExtra().get("filteredDeviceIds"); - assertEquals(Arrays.asList(400L, 200L, 300L), filteredIds); // 保持配置顺序,不是[200, 300, 400] + assertEquals(2, filteredIds.size()); + assertEquals(Arrays.asList(400L, 200L), filteredIds); // 保持配置顺序,只取前2个 } @Test