重构大开关语句

皮130

我有以下switch语句:

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:
  ...

等等。

模式每次都相同,但有一些小的变化。我该如何重构?我想重构外壳中的样式,并且我也试图删除整个开关块。那可能吗?

戴夫·牛顿

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

没有较大的上下文,就很难提供合理的重构,甚至很难确定这种重构是否值得付出努力和进行额外的维护。

简而言之,您type需要处理许多问题。除了开关之外,您还可以实现命令模式,其中每种类型都是小类或简单对象。(使用类可以使在“执行上下文”中传递的内容稍微容易一些,该“执行上下文”包含代码段中未显示的变量。)

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


您将有一个基本类型处理程序。这结束了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

简单的对象或立即函数可能是一个明显较小的实现,尽管不一定容易推理。它们还具有能够关闭本地已有变量的优点。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章