Шаблон Javascript Builder не видит объявленную переменную - PullRequest
0 голосов
/ 05 ноября 2019

Я пытаюсь реализовать шаблон Builder для генерации строки параметров JSON, которые передаются в библиотеку для генерации виджетов. Я не могу понять, почему в console.log ниже это this.options не определено.

let Options = function(options) {
  this.options = options;
}

let OptionsObjectBuilder = function () {

  let options;

  return {
      addConstantLineToValueAxis: function (lineValue) {
          console.log(this.options); // EQUALS UNDEFINED SO CAN'T ADD TO THIS OBJECT
          this.options.valueAxis.constantLine.value = lineValue;
          return this;
      },
      build: function () {
          return new Options(this.options);
      }
  };
};

let option = new OptionsObjectBuilder().addConstantLineToValueAxis(1000000000).build();

Ответы [ 2 ]

1 голос
/ 05 ноября 2019

Для строителя есть два разных способа хранения временных состояний:

  • В самом объекте строителя (путем установки this.options =)
  • В замыкании (путем установкиoptions =)

Преимущество примера закрытия заключается в том, что состояние временного построителя недоступно извне.

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

Использование состояния объекта построителя - показывает внутреннее состояние

let Task = function(name, description, finished, dueDate) {

    this.name = name;
    this.description = description;
    this.finished = finished;
    this.dueDate = dueDate;
}

let TaskBuilder = function () {
    return {
        setName: function (name) {
            this.name = name;
            return this;
        },
        setDescription: function (description) {
            this.description = description;
            return this;
        },
        setFinished: function (finished) {
            this.finished = finished;
            return this;
        },
        setDueDate: function (dueDate) {
            this.dueDate = dueDate;
            return this;
        },
        build: function () {
            return new Task(this.name, this.description, this.isFinished, this.dueDate);
        }
    };
};

let builder = new TaskBuilder().setName('Task A').setDescription('finish book')
    .setDueDate(new Date(2019, 5, 12));
let task = builder.build();
// Notice the builder does expose the name/description... properties
console.log({builder, task});

Использование переменных закрытия - скрывает внутреннее состояние

let Task = function(name, description, finished, dueDate) {

    this.name = name;
    this.description = description;
    this.finished = finished;
    this.dueDate = dueDate;
}

let TaskBuilder = function () {

    let name;
    let description;
    let isFinished = false;
    let dueDate;

    return {
        setName: function (pName) {
            name = pName;
            return this;
        },
        setDescription: function (pDescription) {
            description = pDescription;
            return this;
        },
        setFinished: function (pFinished) {
            finished = pFinished;
            return this;
        },
        setDueDate: function (pDueDate) {
            dueDate = pDueDate;
            return this;
        },
        build: function () {
            return new Task(name, description, isFinished, dueDate);
        }
    };
};

let builder = new TaskBuilder().setName('Task A').setDescription('finish book')
    .setDueDate(new Date(2019, 5, 12));
let task = builder.build();
// Can't see the name/description... properties on the builder, just the methods
console.log({builder, task});
0 голосов
/ 05 ноября 2019

Полагаю, мне следует использовать this только при возврате в конце функций добавления в шаблоне компоновщика. Я до сих пор не уверен, почему в примере (zetcode.com/javascript/builderpattern) я основывал свой код на ... они устанавливали значения с this.name, но передавали name в своей функции сборки.

// @Steven de Salas: expando function: https://stackoverflow.com/a/44014709/1432612
function buildObjectDepth(obj, base) {
    return Object.keys(obj)
      .reduce((clone, key) => {
        key.split('.').reduce((innerObj, innerKey, i, arr) => 
          innerObj[innerKey] = (i+1 === arr.length) ? obj[key] : innerObj[innerKey] || {}, clone)
        return clone;
    }, Object.assign({}, base));
}

let Options = function(options) {
  this.options = options;
}

let OptionsObjectBuilder = function () {

  let options = {};

  return {
      addConstantLineToValueAxis: function (lineValue) {
         options = buildObjectDepth({"valueAxis.constantLine.value": lineValue}, options);
         return this;
      },
      build: function () {
          return new Options(options);
      }
  };
};

let obj = new OptionsObjectBuilder().addConstantLineToValueAxis(1000000000).build();

str = JSON.stringify(obj);
str = JSON.stringify(obj, null, 4); // indented output.
alert(str);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...