核心是让数量变更行为本身携带边界意识,而非依赖外部判断:用map时通过merge/computeifpresent等原子操作封住非法中间态;用list时将校验封装进cartitem的updatequantity方法;所有入口统一调用clampquantity裁决函数,并在持久化读写时双重校验。
核心是让数量变更行为本身携带边界意识,而不是靠外部反复判断。数据结构不是容器,而是约束的载体——选对结构,边界就自然成立。
用 Map 做键值映射时,靠原子操作封住非法中间态
当购物车用 Map<string integer></string> 存商品 ID 与数量,加减不能直接改值,必须走集合原生方法:
- 加购统一用
merge(productId, 1, Integer::sum)—— 自动处理新增和累加,不需判空 - 减购用
computeIfPresent(productId, (k, v) -> Math.max(0, v - 1))—— 零值自动截断,不越界 - 设为指定值时,始终过一次
Math.max(0, Math.min(target, stock)),上下限一步到位
用 List 存商品对象时,把校验收进实体内部
若购物车是 List<cartitem></cartitem>,每个 CartItem 必须封装数量字段,禁止裸露修改:
- 提供
updateQuantity(int newQty)方法,内部强制执行this.quantity = clampQuantity(newQty, 0, stock) - 加减操作写成
item.updateQuantity(item.getQuantity() + delta),避免中间出现负数或超库存 - 构造函数也校验:传入 -3 或 9999 时,自动归零或压至库存上限,不放脏数据进集合
所有边界规则必须统一出口,不能散落在各处
下限(≥0 还是 ≥1)、上限(≤库存 还是 ≤限购数)这些规则,如果在按钮点击、输入框解析、导入脚本里各自写一遍,必然漏检或不一致:
- 定义一个通用裁决函数:
clampQuantity(int raw, int min, int max) - 所有入口——UI 按钮、API 参数、后台导入、甚至控制台命令——都先调它,再进集合操作
- 父层(如购物车服务)做最终裁决:子组件说“想减 1”,父组件查库存后决定是减 1、减到库存值,还是提示缺货
持久化时再校验,不信任任何落地数据
文件或 localStorage 不是透明管道,而是需要主动消毒的边界:
- 加载时:读出原始 JSON → 对每个 quantity 调
clampQuantity→ 再塞进内存集合 - 保存时:遍历集合,对每个 quantity 再次裁决 → 然后再序列化写入
- 清空购物车时,不只是
clear(),还要同步重置总价、总件数等派生状态,防止残留脏数据











