расширение синглтон-класса в es6 - PullRequest
0 голосов
/ 05 сентября 2018

Мне нужно расширить синглтон-класс в JavaScript.

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

Я попытался удалить super, чтобы не получить экземпляр, но затем я получил ошибку

Должен вызывать супер-конструктор в производном классе, прежде чем получить доступ к 'this' или возврату из производного конструктора

Пример кода:

let instanceA = null;
let instanceB = null;

class A {
  constructor(options) {
    if (instanceA === null) {
      this.options = options;
      instanceA = this;
    }
    return instanceA;
  }
}

class B extends A {
  constructor(options) {
    if (instanceB === null) {
      super()
      console.log('real class is ' + this.constructor.name)
      this.options = options
      instanceB = this;
    }
    return instanceB;
  }
}

const a = new A({
  i_am_a: "aaaaaa"
});

const b = new B({
  i_am_b: "bbbbbb"
}) // this change a 

console.log(b.options)

console.log(a.options)

Ответы [ 3 ]

0 голосов
/ 06 сентября 2018

ну, я не знаю, является ли это лучшим решением, но я проверял, отличается ли имя конструктора от имени класса. если это так, то я позволил ему создать новый экземпляр, потому что это означает, что я пытаюсь расширить класс

вот рабочий пример моего теста

let instanceA = null;
let instanceB = null;

class A {
  constructor(options) {
    this.options = options;
  	
    if (instanceA === null) {
     
      	instanceA = this;
    }
    if(this.constructor.name !== "A"){
    	return this;
    }
    
    return instanceA;
  }
  
  method1(){
    console.log(this.constructor.name)
  }
}

class B extends A {
  constructor(options) {
    if (instanceB === null) {
      super(options)
      instanceB = this;
    }
    return instanceB;
  }
}

const a = new A({
  i_am_a: "aaaaaa"
});a

const b = new B({
  i_am_b: "bbbbbb"
}) 
const c = new A({
  i_am_c: "ccccc"
});
const d = new B({
  i_am_d: "ddddd"
}) 
console.log(a.options)
console.log(b.options)
console.log(c.options)
console.log(d.options)
a.method1();
b.method1();
c.method1();
d.method1();
0 голосов
/ 06 сентября 2018

Итак, во-первых, здесь есть неправильное представление:

Я пытался удалить super, чтобы не получить экземпляр, но затем я получил ошибку

super() вызывает родительский класс ' конструктор в созданном экземпляре дочернего класса (то есть, на что ссылается this). Он не возвращает экземпляр родительского класса. См. Здесь для получения дополнительной информации.

Таким образом, вызов super() совсем не нарушает свойство singleton родительского класса. Он может быть построен только один раз, если реализован правильно.


Имея это в виду, вам следует немного улучшить свой код.

Разумным изменением будет удаление управления экземплярами из конструкторов. Одним из решений будет использование статических конструкторов , которые либо создают синглтон, если экземпляр не существует, либо возвращают созданный экземпляр.

Еще один способ - передать аргументы конструкторам синглтон-классов. На самом деле не имеет смысла передавать аргументы классу, который должен быть создан один раз (вы никогда не будете снова ничего делать с аргументами конструктора). Вы можете просто сделать аргументы свойствами синглтона сразу. Вот SO ответ , поддерживающий этот пункт для синглетонов Java.

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

let instanceA = null;
let instanceB = null;

let counters = { A: 0, B: 0 }; // count class instantiations

class A {
  static getInstance() {
    if (instanceA === null) {
      instanceA = new A();
    }
    return instanceA;
  }
  whoami() {
    const name = this.constructor.name;
    return `${name} #${counters[name]}`;
  }
  constructor() {
    counters[this.constructor.name] += 1;
  }
}

class B extends A {
  static getInstance() {
    if (instanceB === null) {
      instanceB = new B();
    }
    return instanceB;
  }
  constructor() {
    super();
  }
}

const a1 = A.getInstance();
const a2 = A.getInstance();
const a3 = A.getInstance();
const b1 = B.getInstance();
const b2 = B.getInstance();
const b3 = B.getInstance();
console.log(a1.whoami());
console.log(a2.whoami());
console.log(a3.whoami());
console.log(b1.whoami());
console.log(b2.whoami());
console.log(b3.whoami());

Обратите внимание, что B наследует whoami от A и что счетчики вызовов конструктора никогда не увеличиваются после 1.

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

0 голосов
/ 05 сентября 2018

В JavaScript синглтон - это просто литерал объекта.

const a = {
    options: {
        i_am_a: "aaaaaa"
    }
};
const b = {
    options: {
        i_am_b: "bbbbbb"
    }
};

Если вам действительно нужна функция конструктора, вы можете просто написать функцию, которая возвращает объект.

function makeSingleton(options) {

    return {
        options
    }

}

const a = makeSingleton({i_am_a: "aaaaaa"});
const b = makeSingleton({i_am_b: "bbbbbb"});

Здесь нет цепочки наследования, только два литерала объекта. Если вам абсолютно нужен класс, вы можете просто создать его, но это ненужная трата ресурсов и набора текста.

class Singleton {

    constructor(options) {
        this.options = options;
    }

}

const a = new Singleton({i_am_a: "aaaaaa"});
const b = new Singleton({i_am_b: "bbbbbb"});

С точки зрения наследования, если это то, что вам действительно нужно, вы можете использовать Object.create() или Object.assign(), в зависимости от ваших потребностей. Имейте в виду, что оба они мелкие - они работают только на один слой, поэтому изменение свойства options дочернего элемента также изменит свойство options родительского элемента.

const a = {
    options: {
        i_am_a: "aaaaaa"
    },
    getOptions() {
        return this.options;
    }
};
const b = Object.create(a);
b.options.i_am_b: "bbbbbb";
a.options.i_am_b; // -> "bbbbbb"
b.getOptions(); // -> { i_am_a: "aaaaaa", i_am_b: "bbbbbb" }

Конечно, вы можете использовать Object.create() или Object.assign() на options.

Если честно, я думаю, что вам нужна пара экземпляров одного класса или простой литерал объекта без какого-либо наследования.

...