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:全局数量匹配 - 只指定 deviceCount,匹配所有机位的数量
- * - 模式2:指定列表数量匹配 - 同时指定 deviceCount + deviceIds,从指定列表中过滤并匹配数量
+ * - 模式1:全局数量匹配 - 只指定 deviceCount,匹配所有机位的数量 ≥ deviceCount
+ * - 模式2:指定列表数量匹配 - 同时指定 deviceCount + deviceIds,从指定列表中过滤并匹配数量 ≥ deviceCount
*
*
* 配置示例:
*
- * // 模式1:全局数量匹配
+ * // 模式1:全局数量匹配(大于等于)
* {
* "deviceCount": 4
* }
+ * // 匹配:用户有4个或更多机位时匹配成功
*
- * // 模式2:指定列表数量匹配
+ * // 模式2:指定列表数量匹配(大于等于)
* {
* "deviceCount": 2,
* "deviceIds": [200, 300, 400]
* }
+ * // 匹配:从列表中过滤出≥2个机位时匹配成功,只取前2个供数据源使用
*
*
* 模式2匹配逻辑:
*
* - 从 deviceIds 列表中过滤出实际存在的机位
* - 保持配置顺序(不按 deviceId 排序)
- * - 判断过滤后的数量是否等于 deviceCount
- * - 匹配成功后,将过滤后的机位列表存入 context.extra,供数据源解析使用
+ * - 判断过滤后的数量是否 ≥ deviceCount
+ * - 匹配成功后,只取前 deviceCount 个机位存入 context.extra,供数据源解析使用
*
*
* @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