重构大开关声明

时间:2016-12-09 19:45:04

标签: javascript switch-statement refactoring

我有以下开关声明:

switch (type) {
  case 1: // 1 BYTE 8-bit unsigned integer
    pointer = count > 4 ? offset : pointer;
    for (let i = 0; i < count; i++) {
      value += dataView.getUint8(pointer + i);
    }
    tag.value = parseInt(value, 10);
    return tag;
  case 3: // 3 SHORT 16-bit unsigned integer
    pointer = count > 2 ? offset : pointer;
    for (let i = 0; i < count; i++) {
      value += dataView.getUint16(pointer + 2 * i, littleEnd);
    }
    tag.value = parseInt(value, 10);
    return tag;
  case 4: // 4 LONG 32-bit unsigned integer
    pointer = count > 1 ? offset : pointer;
    for (let i = 0; i < count; i++) {
      value += dataView.getUint32(pointer + 4 * i, littleEnd);
    }
    tag.value = parseInt(value, 10);
    return tag;
  case 5:
  ...

等等。

模式每次都是相同的,有一些小的变化。我怎么能重构这个?我想重构案例中的模式,我也试图删除整个开关块。这可能吗?

1 个答案:

答案 0 :(得分:0)

(这可能属于Code Review Stack Exchange。)

如果没有更大的背景,很难提供合理的重构,甚至无法确定这样的重构是否值得付出努力和额外的维护。

简而言之,您需要处理一些type。您可以实现一种命令模式,而不是一个开关,其中每个类型都是一个小类或一个简单的对象。 (使用类可以更容易地传入&#34;执行上下文&#34;其中包含未在代码段中显示的变量。)

为了简洁起见,这是一个(非常)粗略轮廓。

您拥有基本类型处理程序。这包含了dataView循环和标记值设置。由于我不了解上下文,因此我假装有一个您传入的上下文。我包含了所有未在您的代码段中显示的变量。

(我没有包含value,看起来你应该这样,但我不知道意图。)

class BaseTypeHandler {
  constructor(ctx) {
    this.ctx = ctx
  }

  getPointer  = () => throw new Error('Missing getPointer implementation')
  getViewData = () => throw new Error('Missing getViewData implementation')

  getValueFromDataView = () => {
    let value = 0

    for (let i = 0; i < this.ctx.count; i++) {
      value += this.getViewData(i, pointer)
    }

    return value
  }

  getTag = () => {
    const pointer = this.getPointer()
        , value   = this.getValueFromDataView()

    this.ctx.tag.value = parseInt(value, 10)
    return this.ctx.tag
  }
}

每个子类实现所需的唯一功能,这里是如何获取指针,以及如何从dataView获取数据。

class Type1Handler extends BaseTypeHandler {
  getPointer = () => 
    this.ctx.count > 4 ? this.ctx.offset : this.ctx.pointer

  getViewData = (i, pointer) =>
    this.ctx.dataView.getUint8(pointer + i)
}

class Type3Handler extends BaseTypeHandler {
  getPointer = () => 
    this.ctx.count > 2 ? this.ctx.offset : this.ctx.pointer

  getViewData = (i, pointer) =>
    this.ctx.dataView.getUint16(pointer + 2 * i, littleEnd);
}

然后将它们包装在类型处理程序的对象中:

const typeHandlers = {
  1: Type1Handler,
  3: Type3Handler,
  4: Type4Handler
}

const handler = new typeHandlers(type)
    , tag = handler.getTag()

<强> TL; DR

除非您有大量的这些,并且您无法使用数学来确定getPointergetViewData实现,否则您可能希望坚持使用switch

简单对象或直接函数可能是一个非常小的实现,虽然不一定更容易推理。它们还具有能够关闭本地已有变量的优势。