К какому паттерну проектирования относится шаблонный метод (Template Method)?

Ответ

Шаблонный метод (Template Method) относится к категории поведенческих паттернов проектирования.

Суть паттерна: Он определяет "скелет" алгоритма в базовом классе, оставляя реализацию некоторых шагов подклассам. Это позволяет подклассам переопределять отдельные шаги алгоритма, не меняя его общей структуры.

Пример реализации на TypeScript/Node.js:

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

abstract class DataProcessor {
  // Это и есть ШАБЛОННЫЙ МЕТОД.
  public process(): void {
    const data = this.extractData();
    const transformedData = this.transform(data);
    this.save(transformedData);
    this.logCompletion();
  }

  // Шаги, которые должны быть реализованы подклассами.
  protected abstract extractData(): any;
  protected abstract save(data: any): void;

  // Шаг с реализацией по умолчанию (хуки).
  protected transform(data: any): any {
    console.log('Transforming data...');
    return data; // Базовая трансформация
  }

  protected logCompletion(): void {
    console.log('Processing completed.');
  }
}

// Конкретная реализация для работы с файловой системой.
class FileDataProcessor extends DataProcessor {
  protected extractData(): any {
    console.log('Extracting data from file...');
    return { fileContent: 'sample data' };
  }

  protected save(data: any): void {
    console.log(`Saving data to a new file: ${JSON.stringify(data)}`);
  }

  // Можно переопределить и хук, если нужно.
  protected transform(data: any): any {
    const transformed = super.transform(data);
    transformed.processedBy = 'FileProcessor';
    return transformed;
  }
}

// Использование
const processor = new FileDataProcessor();
processor.process();

Где применяется в Node.js экосистеме: Этот паттерн часто лежит в основе классов фреймворков, например, в middleware-цепочках или в абстрактных классах для стратегий аутентификации, где общий поток определен, а детали — реализуются разработчиком.

Ответ 18+ 🔞

Да ты посмотри, какой прикольный паттерн! Шаблонный метод, ёпта. Это когда у тебя есть какой-то процесс, алгоритм, и он как железная дорога: рельсы уже проложены, поезд едет по одному маршруту, но на станциях могут быть разные вокзалы, понимаешь?

В чём соль, блядь: Берёшь базовый класс и говоришь: «Слушай, дружище, вот общий план операции. Мы делаем раз, два, три. Но пункты «раз» и «три» — это твои проблемы, реализуй как хочешь. А пункт «два» — у меня уже есть нормальная базовая версия, но если захочешь — можешь и её переписать». И подклассы уже сами решают, как им выковыривать данные или куда их пихать. Общая структура — неприкосновенна, это святое. Волнение ебать, как всё продумано!

Смотри на примере, чувак. Допустим, у нас класс для обработки данных. Вечный сценарий.

abstract class DataProcessor {
  // Это и есть тот самый ШАБЛОННЫЙ МЕТОД, каркас.
  public process(): void {
    const data = this.extractData(); // Шаг 1: Вытащить (абстрактный)
    const transformedData = this.transform(data); // Шаг 2: Преобразовать (можно переопределить)
    this.save(transformedData); // Шаг 3: Сохранить (абстрактный)
    this.logCompletion(); // Шаг 4: Лог (базовый)
  }

  // Вот эти два метода — дырки, которые надо заткнуть. Абстрактные, ёбана!
  protected abstract extractData(): any;
  protected abstract save(data: any): void;

  // А это — хук. Есть базовая реализация, но если надо — впендюрь свою.
  protected transform(data: any): any {
    console.log('Transforming data...');
    return data; // Просто возвращает как есть
  }

  // И это тоже хук, но его обычно не трогают.
  protected logCompletion(): void {
    console.log('Processing completed.');
  }
}

// А вот конкретный чувак, который работает с файлами.
class FileDataProcessor extends DataProcessor {
  protected extractData(): any {
    console.log('Extracting data from file...');
    return { fileContent: 'sample data' };
  }

  protected save(data: any): void {
    console.log(`Saving data to a new file: ${JSON.stringify(data)}`);
  }

  // Можешь и хук перебить, если не нравится как работает.
  protected transform(data: any): any {
    const transformed = super.transform(data); // Сначала делаем как у родителя
    transformed.processedBy = 'FileProcessor'; // А потом своё г*** добавляем
    return transformed;
  }
}

// Используем, бля!
const processor = new FileDataProcessor();
processor.process();

Где это в Node.js пригождается? Да везде, ёклмн! Все эти фреймворки на этом стоят. Тот же Express — у него middleware цепочка это по сути шаблонный метод: запрос прошёл через общий конвейер, а что делать на каждом этапе — твои заморочки. Или взять абстрактные классы для стратегий — общий поток авторизации описан, а как именно проверять логин-пароль или JWT-токен — это уже твоя манда с ушами. Удивление пиздец, как часто этот паттерн под капотом торчит, а многие его и не замечают.