对象调用某个函数,并将所得结果作为参数,传递给另一个函数。而接受该参数的函数本身也能够调用前一个函数。

让参数接受者去除该项参数,并直接调用前一个函数。
// 修改前
const basePrice = _quantity * _itemPrice
const discountLevel = getDiscountLevel()
const finalPrice = discountedPrice(basePrice, discountLevel)

// 修改后
const basePrice = _quantity * _itemPrice
const finalPrice = discountedPrice(basePrice)

动机

  如果函数可以通过其他途径获得参数值,那么它就不应该通过参数取得该值。过长的参数列会增加程序阅读者的理解难度,因此我们应该尽可能缩短参数列的长度。

  缩减参数列的方法之一就是:看看参数接受端是否可以通过与调用端相同的计算取得参数值。如果调用端通过其所属对象内部的另一个函数来计算参数,并在计算的过程中未曾引入调用端的其他参数,那么你就应该可以将这个计算过程转移到被调用端内,从而去除该项参数。如果你所调用的函数隶属另一个对象,而该对象拥有调用端所属对象的引用,前面所说的这些也同样适用。

  但是,如果参数值的计算过程依赖于调用端的某个参数,那么你就无法去掉被调用端的参数,因为每一次调用动作中,该参数值都有可能不同(这时可以用"已明确函数取代参数"替换为一个函数)。

做法

  • 如果有必要,将参数的计算过程提炼到一个独立的函数中。
  • 将函数本体引用该参数的地方改为调用的新建函数。
  • 每次替换后,修改并测试。
  • 全部替换完成后,使用(移除参数方法)将参数去掉。

范例

以下代码用于计算订单折扣价格:

const _quantity = 10
const _itemPrice = 20

function getPrice () {
  const basePrice = _quantity * _itemPrice
  const discountLevel = _quantity > 100 ? 2 : 1
  const finalPrice = discountedPrice(basePrice, discountLevel)
  return finalPrice
}

function discountedPrice (basePrice, discountLevel) {
  return basePrice * (discountLevel === 2 ? 0.1 : 0.05)
}

首先把计算折扣等级 (discountLevel) 的代码提炼成一个独立函数(getDiscountLevel):

const _quantity = 10
const _itemPrice = 20

function getPrice () {
  const basePrice = _quantity * _itemPrice
  // 这里调用新函数: getDiscountLevel()
  const discountLevel = getDiscountLevel()
  const finalPrice = discountedPrice(basePrice, discountLevel)
  return finalPrice
}

// 提炼出来的获取折扣函数
function getDiscountLevel () {
  return _quantity > 100 ? 2 : 1
}

function discountedPrice (basePrice, discountLevel) {
  return basePrice * (discountLevel === 2 ? 0.1 : 0.05)
}

然后把 discountedPrice() 函数中对 discountLevel 参数的所有引用替换为对 getDiscountLevel() 函数的调用:

const _quantity = 10
const _itemPrice = 20

function getPrice () {
  const basePrice = _quantity * _itemPrice
  const discountLevel = getDiscountLevel()
  // 替换为对函数 getDiscountLevel 的调用
  const finalPrice = discountedPrice(basePrice, getDiscountLevel())
  return finalPrice
}

function getDiscountLevel () {
  return _quantity > 100 ? 2 : 1
}

function discountedPrice (basePrice, discountLevel) {
  // 替换为对函数 getDiscountLevel 的调用
  return basePrice * (getDiscountLevel() === 2 ? 0.1 : 0.05)
}

接下来可以将 getPrice 函数里 discountLevel 变量和 discountedPrice 函数的 discountLevel 参数去掉了:

const _quantity = 10
const _itemPrice = 20

function getPrice () {
  const basePrice = _quantity * _itemPrice
  const finalPrice = discountedPrice(basePrice)
  return finalPrice
}

function getDiscountLevel () {
  return _quantity > 100 ? 2 : 1
}

function discountedPrice (basePrice) {
  // 替换为对函数 getDiscountLevel 的调用
  return basePrice * (getDiscountLevel() === 2 ? 0.1 : 0.05)
}

再去掉其他非必要的参数 (discountedPrice函数里的basePrice参数) 和相应的临时变量:

const _quantity = 10
const _itemPrice = 20

function getPrice () {
  return discountedPrice()
}

function getBasePrice () {
  return _quantity * _itemPrice
}

function getDiscountLevel () {
  return _quantity > 100 ? 2 : 1
}

function discountedPrice () {
  return getBasePrice() * (getDiscountLevel() === 2 ? 0.1 : 0.05)
}

再对 getPrice 和 discountedPrice 使用(内联函数方法),得到最终的代码:

const _quantity = 10
const _itemPrice = 20

function getPrice () {
  return getBasePrice() * (getDiscountLevel() === 2 ? 0.1 : 0.05)
}

function getBasePrice () {
  return _quantity * _itemPrice
}

function getDiscountLevel () {
  return _quantity > 100 ? 2 : 1
}

声明

以上摘抄自《重构 改善既有代码的设计》一书,代码部分由原来的java改写成javascript。目的仅为加深印象和理解,如有侵权请联系。