ES6 — Прикрепить прототип класса к singleton

#javascript #ecmascript-6 #es6-class

#javascript #ecmascript-6 #es6-класс

Вопрос:

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

Например: у меня есть класс ‘worker’, который необходимо «расширить» до существующего экземпляра класса IPC, чтобы он мог обмениваться данными по каналу ipc.

 class Worker {
    constructor(ipc) {
        this.__proto__ = ipc;
        this.__proto__.constructor = Worker;
    }
}
  

И тогда я могу использовать его следующим образом:

 const worker = new Worker(myCurrentIpc);
worker.send('blabla') /* Calls super instance ipc method */
  

Это плохая практика, поскольку она снижает производительность..
https://developer.mozilla.org/nl/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf

И в этом случае метод ‘send’ будет вызываться миллионы раз.

Итак, что бы вы порекомендовали в подобном случае использования?

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

Спасибо

Уточнение:

У меня есть один рабочий «хост» (основной).. У которого уже есть инициализированный экземпляр IPC (node-ipc)..

Когда я когда-либо создаю рабочий «дочерний», я хочу использовать (уже существующий) родительский экземпляр IPC для подключения к дочернему рабочему..

Так что было бы действительно неплохо, чтобы при создании нового Worker({ipc:ipc}) я мог прикрепить worker.prototype к экземпляру IPC.. Таким образом, я могу просто выполнить worker.send(), и экземпляр IPC узнает, что он переходит из основного-> дочернего канала..

Комментарии:

1. Это ipc отдельный класс или просто простой объект или экземпляр класса?

2. ipc — это уже инициализированный экземпляр класса

3. Ваше отношение parentworker-childworker не похоже на отношение подкласса. Здесь вы должны отдавать предпочтение композиции, а не наследованию.

Ответ №1:

Как уже упоминалось, это относится к принципу композиции по принципу наследования. Предполагается, что рабочий объект должен сохранять ipc экземпляр как частную собственность и переносить его методы, если предполагается, что он предоставляет некоторые из них:

 class Worker {
  constructor(ipc) {
    this.ipc = ipc;
  }

  send(...args) {
    return this.ipc.send(...args);
  }
}
  

Ответ №2:

Если вы действительно хотите получить доступ к ipc методам с worker.theIpcMethod помощью, вы можете использовать «фабрику классов», функцию, которая создает класс, расширяющий определенное значение:

 function WorkerClassFactory(ipc) {
    return class Worker extends ipc {
        //contents of Worker class here
    }
}
  

Затем вы создаете конкретный Worker класс или заданный IPC:

 let Worker = WorkerClassFactory(myIpcInstance);

//then somewhere
let worker_instance = new Worker();
worker_instance.doStuff();
  

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


НО!Это действительно странная вещь, я бы действительно рекомендовал просто предоставить свойство только для чтения и использовать его оттуда или даже просто обернуть интерфейс IPC во что-то более простое в использовании (если ваш класс просто предоставляет методы IPC, почему бы не использовать IPC напрямую?).

 class Worker {
    constructor(ipc) {
        this._ipc = ipc;
    }

    get ipc() {
        return this._ipc;
    }
}

new Worker(ipc).ipc.send("asdasdasd");
  

Комментарии:

1. Спасибо за примеры кода @Kroltan… Я в некотором смысле рад, что и вы, и synthet1c продвигаетесь в направлении простого превращения ipc в переменную внутри класса.. Начало казаться, что a далеко продвинул наследование

2. @DutchKev Да, это своего рода злоупотребление прототипным наследованием. Это также непоследовательно, потому что, если вы WorkerClassFactory дважды вызываете одно и то же значение ipc , экземпляры этого класса не обязательно будут instanceof этим рабочим. Конечно, фабрика может кэшировать свои выходные данные, но это полностью усложняет сомнительный обходной путь.

3. @DutchKev В этом и заключается принцип композиции по принципу наследования . Это не эмпирическое правило, но здесь оно полностью применимо.

4. @estus, спасибо за чтение! Я искал какую-нибудь черную документацию о принципе «наилучшей практики», и в основном, как вы указали, где «грань» находится между наследованием и композицией, о которой следует помнить..

Ответ №3:

Мой плохой, я не понял вопроса.

Это может быть немного больше того, что вы ищете.

Здесь мы отделяем IPC объект и передаем его в Worker конструктор, а затем из экземпляра, который вы просто делегируете синглтону IPC.

Как говорится в комментариях, использование class в не требуется.

 // here is a singleton with a single static method. using class in not really
// neccasary here, you could just use an object with a single propery
class IPC {
  static send(val) {
    console.log('IPC::send', val)
  }
}

class Worker {
  // constructor takes the ipc as a variable and saves it to itself
  constructor(ipc) {
    this.ipc = ipc
  }
  // the send method simply calls the ipc send function
  send(val) {
    this.ipc.send(val)
  }
}

// create a new worker
const worker = new Worker(IPC);

worker.send('blabla')  

Комментарии:

1. Спасибо за пример кода @synthet1c, но тогда IPC — это не синглтон, а новый класс.. Я хочу прикрепить «новый» экземпляр к одноэлементному / существующему экземпляру

2. Вы не должны использовать a class для одиночных элементов. Если вы делаете это классом, создайте экземпляры с new помощью, если вам нужен одноэлементный, затем используйте литерал объекта.