You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现无硬编码的颜色与尺寸属性筛选及排序算法?

商品属性可用性检查重构需求

现有问题

  • 硬编码依赖严重:当前代码绑定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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 06:29:56