The Jerusalem PostIRGC labels Trump 'big liar,' says US must admit failure in campaign against IranPunchZuckerberg, Pichai, others to meet Trump as AI safety pressure buildsRTP DesportoJaime Faria falha acesso ao quadro principal do torneio de TóquioBollywood HungamaEXCLUSIVE: Karan Tacker to return as Gaurav Tiwari? Bhay Season 2 likely to go on floors in January 2027InquirerLPA outside PAR may develop into tropical depression within 24 hoursDaily MaverickPATHWAYS TO PEACE: Ukraine hoping SA will announce progress on returning abducted childrenSouth China Morning PostChina mourns death of music legend Liu Huan, voice of 2008 Beijing Olympic theme songRTL BoulevardOpnieuw Nederlandse laadpalenmaker onderuit: BlueMarble faillietColliderLegolas Has Been Officially Confirmed for the Next 'The Lord of the Rings' ReleaseSCMP ChinaCan China’s new satellite coordination standards boost PLA targeting and resilience?La PresseLa revue de presse de Paul Arcand | Le vote stratégique, la vente d’alcool dans les arénas et les meilleurs prix dans les circulaires, vraiment ?VnExpress InternationalVietnamese student clinches top 3 spot in world's largest Chinese-language competition
The Daily Newsstand · Free, Always
Tuesday, September 29, 2026

TypeScript: Как подобрать элегантный “костюмчик” из гардероба вашему коду используя паттерны: Стратегия и Фасад

Translate

Знаешь это чувство, когда открываешь свой шкаф и ничего не можешь найти, потому всё не на своих местах и нет никакой системы куда бы “подсунуть” новую покупку? Ты опаздываешь, нервничаешь, а вместо стильного образа на важную встречу собираешь какой-то винегрет из мятых вещей.

В программировании бывает точно так же. Только вместо шкафа у нас код, а вместо одежды -- куча условий if-else, нагроможденных друг на друга.

Допустим, ты пилишь UI-компонент формы ввода. И у тебя есть набор флагов состояния: empty, info, warning или того хуже, error.

Если писать «в лоб», код превращается в жуткого монстра, которого стыдно показать на код-ревью:

if (this.options.error) {
  this.ui.setBorder('blood-red');
  this.ui.showTooltip('Всё пропало... Шеф!');
  this.ui.blockInput();
} else if (this.options.warning) {
  // ... ещё куча строк кода
} else if (this.options.info) {
  // ... и ещё немного кода
} else if (this.options.empty) {
  // ... и ещ] чуть-чуть
}

Читать это через месяц -- то ещё удовольствие. А если дизайнер скажет: «Слушай, а давай для info добавим ещё и синюю иконку?» Тебе придётся лезть в эту кашу, нарушая все традиции единственности (SRP / SOLID), и молиться, чтобы ничего не сломать.

Сегодня под катом разберём, как навести порядок в гардеробе и сшить коду идеальный «костюмчик», элегантно подружив два паттерна: Стратегию и Фасад. Спойлер: твой код станет чище, а жизнь -- проще.

Стратегия: раскладываем вещи по полочкам

Стратегия -- это как идеальная система хранения. У тебя есть отдельные боксы для галстуков, полки для рубашек и штанга для пиджаков. Ты не сваливаешь всё в одну кучу, а создаёшь набор отдельных, независимых сущностей.

Мы создаём массив validationStrategies. Чтобы TypeScript нас полюбил, набросаем быстрый интерфейс. Каждый элемент этого массива -- это объект с тремя полями:

  1. name -- имя стратегии (чтобы мы понимали, что это за “предмет гардероба”).

  2. match -- условие. Функция, которая отвечает на вопрос: «Эта ситуация подходит под мою стратегию?». В боевом коде это будет набор условий по различным входным данным, но мы не должны забывать про чистоту кода!

  3. apply -- действие. Что конкретно мы делаем. Подбор упакованных костюмов для выхода чтобы мы не мешкали опаздывая на встречу.

interface ValidationOptions {
  value?: string;
  empty?: boolean;
  info?: boolean;
  warning?: boolean;
  error?: boolean;
}

interface ValidationStrategy {
  name: string;
  match: (options: ValidationOptions) => boolean;
  apply: (options: ValidationOptions) => void; // Тут прячется Фасад!
}

Теперь посмотрим на примере наш массив (без фанатизма):

const validationStrategies: ValidationStrategy[] = [
  {
    name: 'error',
    match: (options) => options.error === true,
    apply: (options) => { /* магия преображения */ }
  },
  {
    name: 'warning',
    match: (options) => options.warning === true,
    apply: (options) => { /* ... */ }
  },
  {
    name: 'info',
    match: (options) => options.info === true,
    apply: (options) => { /* ... */ }
  },
  {
    name: 'empty',
    match: (options) => !options.value && options.empty,
    apply: (options) => { /* ... */ }
  },
  // ... и т.п.
];

Шкаф рассортирован. Каждая стратегия инкапсулирована (ООП) и знает только своё дело.

Фасад: прячем бирки, нитки и нижнее бельё

А теперь самое интересное. Что находится внутри функции apply? Там находится Фасад.

Фасад -- это как идеально сидящий пиджак. Никто не видит, сколько раз ты обжегся утюгом, пока его гладил, какие там подплечники и сколько пуговиц пришлось перешить. Все видят только стильный результат.

В нашем случае apply -- это и есть тот самый пиджак. За ним скрывается вся сложная UI/UX логика: изменение CSS-классов, отрисовка тултипов, переключение поля в режим ReadOnly или добавление кнопки-экшена.

Смотри, как это выглядит на практике:

{
  name: 'warning',
  match: (options) => options.warning === true,
  apply: (options) => {
    // Фасад берет на себя всю рутину!
    this.ui.setBorderColor('yellow');
    this.ui.showTooltip('Эй, проверь данные, тут что-то не так');
    this.ui.setReadOnly(false); 
    this.ui.hideActionButton(); 
  }
}

А теперь, попробуем добавить что-нибудь новенькое: trace -- когда мы просто логируем всё для отладки нашего рещения, но не мешаем юзеру):

{
  name: 'trace',
  match: (options) => options.trace === true,
  apply: (options) => {
    this.ui.setBorderColor('transparent');
    this.ui.hideTooltip();
    this.logger.trace('Поле прошло валидацию', options);
  }
}

Мы спрятали всю грязную работу с DOM-элементами и стилями за одним понятным контрактом. Снаружи -- чистота и элегантность.

Примерка! Или как довести процесс до автоматизма?!

Окей, массив есть, стратегии написаны, фасады спрятаны. Как заставить эту машину ехать самой? Всё гениальное просто. Мы берём текущие абстрактные параметры (this.options), которые прилетели в наш класс-потомок без конкретной типизации, а может и с ней для частного случая и ищем первую стратегию, которая скажет: «О, боже! Это именно то что мне сейчас нужно!». И зовёт сама на 2-е свидание и все прочие опции...

// Ищем подходящую стратегию
const activeStrategy = this.validationStrategies.find(s => s.match(this.options));

// Если нашли — "надеваем" её
if (activeStrategy) {
  activeStrategy.apply(this.options);
}

Коротеннечно, правда? Вместо 100500 строк if-else -- три строчки простого и понятного кода.

⚠️ Важный нюанс (Ловушка для новичков -- Не переборщи с парфюмом! И не забудь заправить рубашку в брюки!)

Метод массива find ищет первый подходящий элемент. Это значит, что порядок объектов в validationStrategies критически важен!

Если у тебя одновременно прилетели флаги warning: true и error: true, сработает та стратегия, которая лежит в массиве выше. Поэтому всегда ставь самые критичные состояния (error, warning) в самое начало массива, а фоновые (info, empty) -- в конец. Ты сам управляешь приоритетами, просто перетаскивая объекты мышкой в IDE. Никаких вложенных условий, только сортировка массива. А если ты за полный контроль и жёсткое доминирование -- позаботься о сортировке!

Почему подготовленный «костюм» удобен в повседневной жизни?

  1. Open/Closed Principle (OCP). Нужно добавить новый флаг super_mega_error? Ты просто создаёшь новый объект и пушишь его в массив. Тебе вообще не нужно трогать основной код компонента и метод find. Код открыт для расширения, но закрыт для модификации.

  2. Легко тестить. Хочешь проверить, правильно ли работает warning в Unit-тестах? Просто возьми этот объект из массива, скорми ему фейковые options и замокай this.ui. Не нужно эмулировать весь компонент целиком.

  3. Переиспользуемость. Завтра тебе скажут сделать точно такую же валидацию, но для другого компонента? Ты просто импортируешь массив validationStrategies и используешь его там.

  4. Читаемость. Открыл файл, посмотрел на массив -- сразу понял все возможные состояния UI и бизнес-логику. Это как посмотреть на человека и сразу понять, куда он собрался: на пляж или на деловую встречу.

Итог

Паттерны проектирования -- это не скучная теория из учебников для заучивания на собеседованиях. Это реальные инструменты, которые экономят нервы. Стратегия помогает не потеряться в куче условий и соблюдает SOLID, а Фасад прячет всю UI-кухню под капотом, предоставляя чистый API.

Так что в следующий раз, когда откроешь свой «шкаф» и ужаснёшься от бардака -- просто вспомни про карточки стратегий. И подбери своему коду костюмчик по фигуре и месту встречи. 😉

А как вы обычно решаете проблему множественных состояний UI? Делитесь в комментариях, всегда интересно посмотреть на чужие архитектурные решения (и, чего греха таить, на элегантные костыли)!

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.