如何实现无硬编码的颜色与尺寸属性筛选及排序算法?
商品属性可用性检查重构需求
现有问题
- 硬编码依赖严重:当前代码绑定
CharacteristicEnum中的color、dressSize等枚举值,新增或修改属性(如版型、材质)后无法适配,扩展性极差。 - 属性切换逻辑缺陷:用户初始选择黑色M进入详情页后,若S尺寸被禁用,切换至仅支持S的紫色款时会受限制,存在初始选择与可用属性的依赖冲突。
- 排序逻辑缺失:颜色、尺寸等属性无合理排序规则,展示顺序混乱。
参考数据结构
[ {"name": "Purple","characteristics": [{"name": "dress_size","value": "S"},{"name": "color","value": "Purple"}]}, {"name": "black, size XL","characteristics": [{"name": "dress_size","value": "XL"},{"name": "color","value": "Black"}]}, {"name": "black, size L","characteristics": [{"name": "dress_size","value": "L"},{"name": "color","value": "Black"}]}, {"name": "black, size M","characteristics": [{"name": "dress_size","value": "M"},{"name": "color","value": "Black"}]}, {"name": "black, size S","characteristics": [{"name": "dress_size","value": "S"},{"name": "color","value": "Black"}]} ]
当前硬编码依赖片段
final Map<CharacteristicEnum, Set<String>> availableAttributes;
现有完整代码
bool isAttributeAvailable(CharacteristicEnum characteristic, String value) { final Map<CharacteristicEnum, String> selectedAttributes = selectedAttributeMap; final Iterable<ProductDetailsModel>? availableProducts = productOffer.value?.where((ProductDetailsModel product) { return selectedAttributes.entries.every((MapEntry<CharacteristicEnum, String> entry) { if (entry.key == characteristic) return true; final List<String>? attributeValues = product.groupedCharacteristics[entry.key]; return attributeValues != null && attributeValues.contains(entry.value); }); }); if (availableProducts != null && availableProducts.isNotEmpty) { for (final ProductDetailsModel product in availableProducts) { final List<String>? availableValues = product.groupedCharacteristics[characteristic]; if (availableValues != null && availableValues.contains(value)) { return true; } } } if (characteristic == CharacteristicEnum.color) { return _canSwitchToAvailableAttribute(characteristic, value); } return false; } bool _canSwitchToAvailableAttribute(CharacteristicEnum characteristic, String value) { for (final ProductDetailsModel product in productOffer.value ?? <ProductDetailsModel>[]) { final List<String>? availableValues = product.groupedCharacteristics[characteristic]; if (availableValues != null && availableValues.contains(value)) { return true; } } return false; } onAsync<SelectAttributeProductDetailEvent>((SelectAttributeProductDetailEvent event) async* { final Map<CharacteristicEnum, String> selectedMap = state.selectedAttributeMap.copy(); selectedMap[event.nameAttribute] = event.attributeValue; if (event.nameAttribute == CharacteristicEnum.color) { final Iterable<String>? availableSizesForNewColor = state.productOffer.value ?.where( (ProductDetailsModel product) => product.groupedCharacteristics[CharacteristicEnum.color]?.contains(event.attributeValue) ?? false, ) .expand( (ProductDetailsModel product) => product.groupedCharacteristics[CharacteristicEnum.dressSize] ?? <String>[], ); final String? currentSize = selectedMap[CharacteristicEnum.dressSize]; if (currentSize == null || (availableSizesForNewColor != null && !availableSizesForNewColor.contains(currentSize))) { if (availableSizesForNewColor != null && availableSizesForNewColor.isNotEmpty) { selectedMap[CharacteristicEnum.dressSize] = availableSizesForNewColor.first; } } } final Map<CharacteristicEnum, Set<String>> availableAttributes = <CharacteristicEnum, Set<String>>{}; for (final CharacteristicEnum characteristic in state.groupedCharacteristics.keys) { availableAttributes[characteristic] = state.groupedCharacteristics[characteristic] ?.where((String value) => state.isAttributeAvailable(characteristic, value)) .toSet() ?? <String>{}; } yield state.copyWith( selectedAttributeMap: selectedMap, availableAttributes: availableAttributes, ); });
重构方案
1. 移除枚举硬编码,改用动态属性标识
将所有依赖CharacteristicEnum的类型替换为String,实现属性动态适配:
selectedAttributeMap改为Map<String, String>availableAttributes改为Map<String, Set<String>>groupedCharacteristics改为Map<String, List<String>>
2. 修复属性可用性判断逻辑
取消对特定属性的特殊判断,统一处理所有属性的可用性:
bool isAttributeAvailable(String characteristic, String value) { final Map<String, String> selectedAttributes = selectedAttributeMap; // 筛选符合已选其他属性的商品集合 final Iterable<ProductDetailsModel>? availableProducts = productOffer.value?.where((product) { return selectedAttributes.entries.every((entry) { if (entry.key == characteristic) return true; final attrValues = product.groupedCharacteristics[entry.key]; return attrValues != null && attrValues.contains(entry.value); }); }); // 检查当前属性值是否在可用商品中存在 if (availableProducts?.isNotEmpty == true) { return availableProducts!.any((product) { final values = product.groupedCharacteristics[characteristic]; return values != null && values.contains(value); }); } // 无已选属性时,直接检查该值是否存在于任意商品 return productOffer.value?.any((product) { final values = product.groupedCharacteristics[characteristic]; return values != null && values.contains(value); }) ?? false; }
3. 动态处理属性联动逻辑
通过预设关联规则替代硬编码的属性联动,可扩展任意属性组合:
onAsync<SelectAttributeProductDetailEvent>((event) async* { final Map<String, String> selectedMap = state.selectedAttributeMap.copy(); selectedMap[event.nameAttribute] = event.attributeValue; // 可从后端配置或前端扩展的属性关联规则 const attributeRelations = { "color": ["dress_size"], // 可新增其他关联,如"size": ["length"] }; final relatedAttrs = attributeRelations[event.nameAttribute]; if (relatedAttrs != null) { for (final relatedAttr in relatedAttrs) { final currentRelatedValue = selectedMap[relatedAttr]; if (currentRelatedValue == null) continue; // 获取当前属性对应的关联属性可用值集合 final availableRelatedValues = state.productOffer.value ?.where((product) { final attrValues = product.groupedCharacteristics[event.nameAttribute]; return attrValues != null && attrValues.contains(event.attributeValue); }) .expand((product) => product.groupedCharacteristics[relatedAttr] ?? <String>[]) .toSet(); // 当前关联值不可用时,自动切换到第一个可用值 if (availableRelatedValues?.isNotEmpty == true && !availableRelatedValues!.contains(currentRelatedValue)) { selectedMap[relatedAttr] = availableRelatedValues.first; } } } // 重新计算所有属性的可用值 final Map<String, Set<String>> availableAttributes = {}; for (final characteristic in state.groupedCharacteristics.keys) { availableAttributes[characteristic] = state.groupedCharacteristics[characteristic] ?.where((value) => state.isAttributeAvailable(characteristic, value)) .toSet() ?? {}; } yield state.copyWith( selectedAttributeMap: selectedMap, availableAttributes: availableAttributes, ); });
4. 实现属性值排序算法
添加可扩展的排序规则,支持不同属性的自定义排序:
// 预设排序规则,可从后端获取或前端扩展 const sizeOrder = {"S": 0, "M": 1, "L": 2, "XL": 3, "XXL": 4}; const colorOrder = {"Black": 0, "White": 1, "Purple": 2}; // 通用排序方法 List<String> sortAttributeValues(String characteristic, List<String> values) { switch (characteristic) { case "dress_size": return values..sort((a, b) => sizeOrder[a]!.compareTo(sizeOrder[b]!)); case "color": return values..sort((a, b) => colorOrder[a]!.compareTo(colorOrder[b]!)); default: // 默认按字母排序 return values..sort(); } } // 在计算可用属性时应用排序 availableAttributes[characteristic] = state.groupedCharacteristics[characteristic] ?.where((value) => state.isAttributeAvailable(characteristic, value)) .toList() .let((list) => sortAttributeValues(characteristic, list)) .toSet() ?? {};
内容的提问来源于stack exchange,提问作者inkwelll075
相关产品推荐
相关产品推荐

