Как добавить цепочку функций из одного класса в другой? - PullRequest
1 голос
/ 30 октября 2019

Я пытаюсь разработать игровой движок для личного использования в JS. Я хочу, чтобы мой движок мог использовать элементы отдельных классов. Одна из таких проблем, которую я пытаюсь решить, - это связывание методов из одного класса (скажем, математического класса, который связывает функции) с моей главной функцией.

Вот пример того, как я хочу, чтобы он выглядел следующим образом:

let game = new Engine()
game.operator(5).sum(3).divide(2)

Вот то, что может быть в моем коде, хотя я не уверен, что мне делать.

class Engine {
   constructor() {
    //Set up engine here
    /* This is where I am unsure how to link the following operator class to this one. 
    * Do I put it here in constructor or ...
    */

   }
   /* ... do I put it here? (Or not in this class at all?)
   *
   * This is what I tried doing as a function
   *
   * operator(input) {
   *    let op = new Operator(input);
   * }
   */
}
class Operator {
    /*The following class is different than the one I am using, but follows similar syntax: 
    * Basic usage: operator(5).sum(3, 4) => Should output 12
    * How the class works is mostly irrelevant, just know it chains methods.
    */
    constructor(input) {
        this.input = input;
        this.answer = this.input;
    }
    sum() {
        let a = arguments[0]
        for(var i = 1; i < arguments.length; i++) {
            a += arguments[i];
        }
        this.answer += a;
        return this;
    }
    divide() {
        let a = arguments[0];

        for(var i = 1; i < arguments.length; i++) {
            a *= arguments[i];
        }
        this.answer /= a;
        return this;
    }

}

Как мне получить один класс? умеет цеплять методы из разных классов?

Ответы [ 2 ]

2 голосов
/ 30 октября 2019

Шаблон для формирования цепочки - это сохранение экземпляром состояния цепочки и предоставление метода 'value', который возвращает состояние цепочки. Я полагаю, что для цепочки между двумя классами мне нужен специальный метод значений, который возвращает экземпляр другого класса. (Чтобы ориентировать читателя, назовите его так, чтобы это указывало на изменение типа) ...

class ObjectA {
  constructor(string) {
    this.chainValue = string
    this.string = string
  }

  transformA() {
    this.chainValue = this.chainValue.toUpperCase()
    return this
  }

  transformB() {
    this.chainValue = this.chainValue + "bar"
    return this
  }

  // the regular value method
  get value() {
    return this.chainValue
  }

  // like the value method, but named to explicitly return MyNumber
  get numberValue() {
    return new MyNumber(this.value.length)
  }
}

class MyNumber {
  constructor(int) {
    this.chainValue = int
    this.int = int
  }
  
  add(n) {
    this.chainValue += n
    return this
  }
  
  get value() {
    return this.chainValue
  }
}

let a = new ObjectA("foo")
console.log(
  a
  .transformB()   // append "bar"
  .transformA()   // convert to upper case
  .numberValue    // return a number (arbitrarily, the length of the chain state)
  .add(12)        // add 12
  .value          // expect 18
)
2 голосов
/ 30 октября 2019

Вы можете использовать прокси для этой цели.

    class Engine {
    operator() {
      // code
      console.log('call operator')
    }
  }
  class Operator {
    sum() {
      // code
      console.log('call sum')
    }

    divide() {
      console.log('call divide')
    }
  }

  class SuperOperator {
    negate() {
      console.log('call negate')
    }
  }

  const operator = new Operator();
  const superOperator = new SuperOperator();
  const engine = new Engine();


  const objectsToChainFrom = [
    engine,
    operator,
    superOperator,
  ];

  // create helper function for proxy
  function wrapper(originalMethod, ctx) {
    return function () {
      originalMethod.apply(ctx, arguments);
      // return proxy;
      return this;
    }
  }

  var proxy1 = new Proxy(objectsToChainFrom, {
    get(target, methodToCall, receiver) {
      const objectWithMethod = target.find(el => el[methodToCall]);
      return wrapper(objectWithMethod[methodToCall], objectWithMethod)
    }
  });

  proxy1
    .sum()
    .operator()
    .divide()
    .negate()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...