Это хорошая идея для завышения стоимости метода? - PullRequest
0 голосов
/ 21 мая 2019

У меня есть 3 класса, все расширяют предыдущий.
Сущность -> Тело -> Игрок
У каждого есть die() метод, который делает очень разные вещи.
Entity.die() будет вызывать дБ
Body.die() оживит тело
Player.die() вызывает пользовательский интерфейс и воспроизводит специальный звук.

Я не хочу вручную вызывать 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 ]

1 голос
/ 21 мая 2019

Common Lisp имеет что-то похожее .Когда вы определяете метод в производном классе, вы можете решить, должен ли этот метод выполняться:

  • :before (т.е. базовый метод будет вызываться автоматически после специализированного)
  • :after (т.е. базовый метод будет вызываться автоматически перед специализированным)
  • :around (т.е. будет вызываться только специализированный метод, но внутри его тела вы можете вызывать базовый метод с помощью call-next-methodэто специальный синтаксис, который позволяет вызывать базовый метод либо с параметрами, указанными вызывающей стороной, либо с параметрами, которые вы хотите вместо этого передать.)

Например, в C ++ для общих методов доступно только around(но без возможности вызова базовой версии с исходными параметрами) и принудительно использует before в конструкторе и after в деструкторах.

1 голос
/ 21 мая 2019

Я понимаю желание не повторять код и создавать код, который затрудняет ошибки и забвение вещей.Но у вас все еще есть код, который вам нужно запомнить, чтобы подключиться.Например, вместо того, чтобы звонить 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()
...