过度收费是个好主意吗?

时间:2019-05-21 05:39:10

标签: javascript overloading

我有3个班级,都扩展了上一个班级。
实体->身体->播放器
每个人都有一个die()方法,它们的作用截然不同。
Entity.die()将调用数据库
Body.die()将为身体设置动画
Player.die()将调用UI并播放特殊声音。

我不想在Entity.die()方法内手动调用Body.die,主要是因为我有很多类和很多常用方法,而且我也不想忘记什么。

我写了这段代码来完成此操作,错误堆栈很容易理解,并指向正确的行。

function overLoadMethods (parent, children) {
  const methods = {}
  for (let [fname, fn] of Object.entries(parent)) {
    if (typeof fn === 'function') {
      if (children[fname]) {
        methods[fname] = function () {
          fn()
          children[fname]()
        }
        Object.defineProperty(methods[fname], 'name', { value: fname })
      } else {
        methods[fname] = fn
      }
    }
  }
  return methods
}

function createEntity () {
  return {
    die: () => {
      console.log(new Error().stack)
      console.log('entity die')
    }
  }
}

const bodyMethods = {
  die: () => {
    console.log(new Error().stack)
    console.log('body die')
  }
}

function createBody () {
  const entity = createEntity()
  const overLoadedMethods = overLoadMethods(entity, bodyMethods)
  return {
    ...entity,
    ...bodyMethods,
    ...overLoadedMethods
  }
}

const playerMethods = {
  die: () => {
    console.log(new Error().stack)
    console.log('player die')
  }
}

function createPlayer () {
  const body = createBody()
  const overLoadedMethods = overLoadMethods(body, playerMethods)
  return {
    ...body,
    ...playerMethods,
    ...overLoadedMethods
  }
}

const player = createPlayer()
// will call Entity.die() then Body.die() then Player.die()
player.die()

一切正常,但我以前从未见过这种模式,我想这是我不知道的充分理由。 有人可以指出这种模式的弱点吗(肯定有)?

2 个答案:

答案 0 :(得分:1)

我理解不重复代码和创建代码的愿望,这使得代码难以出错和遗忘。但是您仍然有需要记住的代码。例如,您不必呼叫Entity.die(),而需要呼叫overLoadMethods()。我不确定这是否优于常规类和调用super.die()

您可以使用ES6类获得链式方法的行为(也可以使用原型获得它)。这有很多优点:

•模式已融入语言。
•很明显看到父母/孩子的关系
•有很多关于不同模式的评论,理论和例子

class Entity {
  die() {
    // Entity-specific behavior
    console.log('entity die')
  }
}

class Body extends Entity {
  die() {
    super.die()
    // Body-specific behavior
    console.log('body die')
  }
}

class Player extends Body {
  die() {
    super.die()
    // Player-specific behavior
    console.log('player die')
  }
}


const player = new Player
// will call Entity.die() then Body.die() then Player.die()
player.die()

答案 1 :(得分:1)

通用Lisp有something similar。在派生类中定义方法时,可以决定是否应执行此方法:

  • :before(即在专门的方法之后将自动调用基本方法)
  • :after(即基本方法将在专用方法之前自动调用)
  • :around(即,仅将调用专用方法,但是您可以在其主体内部使用call-next-method调用基本方法,这是一种特殊语法,允许使用由指定的参数调用基本方法调用方或您要传递的参数。

例如,C ++仅将around用于常规方法(但不能使用原始参数调用基本版本),并强制在构造函数中使用before,在构造函数中使用after破坏者。