#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
помощью, если вам нужен одноэлементный, затем используйте литерал объекта.