Revealing Constructor — Открытый конструктор
Передача функции в конструктор, которая получает «инструменты» внутреннего состояния. Не из GoF, но в JS — повсеместно. Канонический пример:
new Promise((resolve, reject) => ...).
Проблема
Хочется передать в объект поведение, не наследуя от него и не подменяя методы. При этом поведение должно иметь доступ к внутренним «рычагам» объекта (как resolve/reject у промиса) — но эти рычаги не должны быть публичными.
Решение
- Конструктор принимает функцию-callback.
- Функция получает внутренние controls объекта как аргументы.
- Controls не доступны снаружи объекта — только в этом callback'е.
Пример в JS
// Промис — каноничный revealing constructor
const p = new Promise((resolve, reject) => {
setTimeout( => resolve(42), 1000);
});
// resolve/reject не доступны снаружи — только через .then/.catch
// Transform stream
const transform = new Transform({
transform(chunk, enc, cb) { cb(null, chunk.toUpperCase()); },
});
// Свой Future без состояния
class Future {
constructor(executor) {
this.executor = executor; // не вызываем сразу
}
subscribe(observer) {
this.executor(observer); // вызываем при подписке
}
}
const f = new Future((emit) => {
let i = 0;
setInterval( => emit(i++), 1000);
});
f.subscribe(console.log);
Где используется в JS-экосистеме
new Promise(executor)— главный примерnew TransformStream({ transform })— Web/Node Streamsnew ReadableStream({ start, pull, cancel })— Streams APIArray.from({ length: 5 }, (_, i) => i)— фабрика-функция в конструкторnew Proxy(target, handler)— handler как открытый конструктор- MobX
observable(obj, { ... })— конфигурация через объект-функцию
Подводные камни
- Не путать с Builder: Builder возвращает себя, revealing constructor принимает executor.
- Не путать с Strategy: Strategy — выбор алгоритма; revealing — инжекция поведения с доступом к внутреннему API.
- Executor вызывается в конструкторе — может стрелять до завершения инициализации (если до
this.x = ...). - В Promise executor вызывается сразу синхронно — это часто сюрприз.
Главные тезисы автора
- «В банде 4 его нет, но он очень типичен для JS-мира».
- «Позволяет без наследования переопределять поведение».
- «TransformStream — самый простой пример»: функция трансформации в конструктор.
- Работает благодаря функциям первого класса в JS.
- Future без состояния и многоразовый: можно композировать, в отличие от Promise.
- Промис = revealing constructor: callback с
resolve/rejectпереводит между состояниями. - Три способа передачи значения: константа, функция-геттер, функция с callback — третий и есть revealing constructor.
🎓 Источники
- 🎓 Паттерн Revealing Constructor — открытый конструктор · 2019-05-14
- Future без состояния и многоразовый
- Три способа передачи значения
- Промис как пример паттерна
- Подписка до и после resolve
- 🎓 Future Asynchrony on Stateless Futures · 2019-05-14
- 🎓 GoF Patterns Обзор всех паттернов · 2025-04-29
- Открытый конструктор — JS-специфика, замена наследованию