Где в ноде используется паттерн Revealing constructor (открытый конструктор, есть много таких мест)?nodejs-11

Что такое Revealing Constructor?

Паттерн Revealing Constructor (открытый конструктор) — это подход, когда конструктор класса принимает функцию, которой раскрываются приватные методы/данные, позволяя инициализировать объект с контролируемым доступом к его внутренностям.

Характеристики:

  1. Конструктор принимает callback (revealer)
  2. Внутри конструктора callback вызывается с ограниченным API
  3. Внешний код не может получить доступ к внутренним методам после создания

Примеры в Node.js

1. Promise — самый известный пример

const promise = new Promise((resolve, reject) => {
  // Здесь доступны только resolve/reject
  setTimeout(() => resolve('Done'), 100);
});

// Снаружи нет доступа к resolve/reject

2. EventEmitter с ограниченным API

Некоторые реализации позволяют создавать эмиттеры с контролируемыми правами:

const { EventEmitter } = require('events');

class ControlledEmitter {
  constructor(executor) {
    const emitter = new EventEmitter();
    executor({
      emit: emitter.emit.bind(emitter),
      addListener: emitter.on.bind(emitter)
    });
    this.emitter = emitter;
  }
}

const ce = new ControlledEmitter(({ emit }) => {
  emit('data', 'secret'); // Доступно только при создании
});

3. stream.Writable и stream.Readable

При создании кастомных стримов:

const { Writable } = require('stream');

const ws = new Writable({
  write(chunk, encoding, callback) {
    // Этот метод доступен только внутри конструктора
    console.log(chunk.toString());
    callback();
  }
});

4. worker_threads.Worker

При создании воркера:

const { Worker } = require('worker_threads');

const worker = new Worker(`
  const { parentPort } = require('worker_threads');
  parentPort.on('message', (msg) => {
    // Обработчик доступен только при создании
  });
`, { eval: true });

5. new Cluster.Worker

В кластерном API:

const cluster = require('cluster');

if (cluster.isMaster) {
  const worker = cluster.fork();
  // worker.exposedMethod доступен только в этом контексте
}

Как это работает внутри?

Рассмотрим упрощенную реализацию:

class SecureContainer {
  #secret = 42; // Приватное поле

  constructor(executor) {
    const controller = {
      getSecret: () => this.#secret,
      setSecret: (val) => { this.#secret = val; }
    };
    executor(controller); // Открываем API только на этапе построения
  }

  get publicValue() {
    return this.#secret / 2;
  }
}

const instance = new SecureContainer(({ setSecret }) => {
  setSecret(100); // Можно установить только при создании
});

console.log(instance.publicValue); // 50
console.log(instance.#secret); // SyntaxError: Private field must be declared in an enclosing class

Преимущества паттерна в Node.js

  1. Контролируемая инициализация:

    • Ограниченный доступ к внутренним методам
    • Гарантированная настройка объекта
  2. Безопасность:

    • Невозможно изменить критичные параметры после создания
    • Инкапсуляция внутренней логики
  3. Гибкость:

    • Разные уровни доступа при создании и использовании
    • Возможность создания иммутабельных объектов

Резюмируем

  1. Revealing Constructor широко используется в Node.js для:

    • Контролируемого создания объектов (Promise)
    • Ограничения доступа к критичным методам (EventEmitter)
    • Настройки поведения при инициализации (stream.Writable)
  2. Ключевые особенности:

    • Доступ к внутренним методам только при создании
    • Полная инкапсуляция после конструирования
    • Гибкая настройка начального состояния
  3. Где искать:

    • Все асинхронные API (Promise, Worker)
    • Системы обработки событий
    • Потоковые интерфейсы

Паттерн особенно полезен в API, где важно ограничить доступ к критически важным методам после инициализации объекта.