重构询价逻辑

使用策略模式重构多条件询价代码

问题

电商系统中,不同用户类型有不同的折扣策略:

  • 普通用户:原价
  • 会员用户:9 折
  • VIP 用户:8 折
  • 超级 VIP:7 折 + 满 100 减 20

原始代码使用大量 if-else,如何重构使其更易维护和扩展?

解答

原始代码(问题代码)

function getPrice(userType, price) {
  if (userType === 'normal') {
    return price
  } else if (userType === 'member') {
    return price * 0.9
  } else if (userType === 'vip') {
    return price * 0.8
  } else if (userType === 'superVip') {
    const discounted = price * 0.7
    return discounted >= 100 ? discounted - 20 : discounted
  }
  return price
}

问题:每次新增用户类型都要修改函数,违反开闭原则。

策略模式重构

// 策略对象:每种用户类型对应一个计价函数
const priceStrategies = {
  normal(price) {
    return price
  },
  member(price) {
    return price * 0.9
  },
  vip(price) {
    return price * 0.8
  },
  superVip(price) {
    const discounted = price * 0.7
    return discounted >= 100 ? discounted - 20 : discounted
  }
}

// 询价函数:根据用户类型调用对应策略
function getPrice(userType, price) {
  const strategy = priceStrategies[userType]
  return strategy ? strategy(price) : price
}

// 使用
console.log(getPrice('normal', 100))   // 100
console.log(getPrice('member', 100))   // 90
console.log(getPrice('vip', 100))      // 80
console.log(getPrice('superVip', 200)) // 120 (200 * 0.7 - 20)

支持动态扩展

// 创建可扩展的询价器
function createPricer(strategies = {}) {
  return {
    // 添加新策略
    addStrategy(type, fn) {
      strategies[type] = fn
      return this
    },
    // 计算价格
    getPrice(type, price) {
      const strategy = strategies[type]
      return strategy ? strategy(price) : price
    }
  }
}

// 使用
const pricer = createPricer()
  .addStrategy('normal', price => price)
  .addStrategy('member', price => price * 0.9)
  .addStrategy('vip', price => price * 0.8)

// 后续新增策略,无需修改原有代码
pricer.addStrategy('newYear', price => price * 0.5)

console.log(pricer.getPrice('vip', 100))     // 80
console.log(pricer.getPrice('newYear', 100)) // 50

结合 Map 实现

// 使用 Map 存储策略,支持任意类型作为 key
const strategies = new Map([
  ['normal', price => price],
  ['member', price => price * 0.9],
  ['vip', price => price * 0.8]
])

function getPrice(userType, price) {
  const strategy = strategies.get(userType)
  return strategy ? strategy(price) : price
}

// 新增策略
strategies.set('superVip', price => {
  const discounted = price * 0.7
  return discounted >= 100 ? discounted - 20 : discounted
})

关键点

  • 策略模式:将算法封装成独立函数,通过映射表查找调用
  • 开闭原则:新增策略只需添加映射,无需修改主函数
  • 消除 if-else:用对象/Map 的键值查找替代条件判断
  • 单一职责:每个策略函数只负责一种计价逻辑
  • 易于测试:每个策略可独立进行单元测试