Adapter
Адаптер — структурный паттерн, который позволяет объектам с несовместимыми интерфейсами работать вместе. Это «переходник» между тем, что вам прислали, и тем, что вам нужно.
Во Frontend-разработке это, пожалуй, самый частый паттерн. Бэкенд (особенно если это Legacy) часто отдает данные в формате, который неудобен для UI. Вместо того чтобы переписывать компоненты под странный формат API, мы пишем функцию-адаптер.
flowchart LR
UI["React Component"] -- "Expects: { id, title }" --> Adapter["Data Adapter"]
Adapter -- "Transforms Data" --> Backend["Legacy API"]
Backend -- "Returns: { ID_VAL, t_text }" --> Adapter
Adapter -- "Returns: { id, title }" --> UI
Сильные стороны:
- Чистый код компонентов: Ваш UI не знает про странные поля типа
user_id_v2с бэкенда. Он работает с чистымuserId. - Легкий рефакторинг: Если бэкенд изменит API, вы поправите только Адаптер, не трогая сотни компонентов.
Нормализация данных
Представьте, что вы получаете список пользователей. Бэкенд шлет дату рождения строкой, а имя и фамилию — разными полями. Компонент же хочет готовое имя и объект Date.
// 1. Данные от сервера (неудобные)
const apiResponse = {
user_id_val: 101,
first_name: "John",
last_name: "Doe",
dob: "1990-01-01"
};
// 2. Адаптер (Чистая функция)
const adaptUser = (serverData) => ({
id: serverData.user_id_val,
fullName: `${serverData.first_name} ${serverData.last_name}`,
birthDate: new Date(serverData.dob),
isAdmin: false // Дефолтное значение, которого нет в API
});
// 3. Использование в UI
const user = adaptUser(apiResponse);
console.log(user.fullName); // "John Doe"
Decorator
Декоратор (Decorator) — паттерн, позволяющий динамически добавлять объекту (или функции) новую функциональность, оборачивая его в полезную «обертку».
Принцип «Матрешки»
graph TD
Client --> Decorator["Decorator (Logging)"]
Decorator --> Component["Core Component (Button)"]
style Decorator fill:#f9f,stroke:#333
style Component fill:#ccf,stroke:#333
В объектно-ориентированном программировании декораторы расширяют классы. В функциональном JS и React декораторы — это функции высшего порядка (HOC) или просто обертки.
Higher-Order Components (HOC)
В мире React этот паттерн долгое время был стандартом (сейчас его вытесняют хуки, но принцип обертки остался). Допустим, у нас есть обычная кнопка, и мы хотим добавить ей логику аналитики, не меняя код кнопки.
// Базовый компонент
const SimpleButton = (props) => {
return <button onClick={props.onClick}>{props.label}</button>;
};
// Декоратор (функция-обертка)
const withAnalytics = (Component) => {
return (props) => {
const handleClick = () => {
console.log("Analytics: Button clicked!"); // Добавленная логика
if (props.onClick) props.onClick();
};
// Рендерим исходный компонент с подмененным onClick
return <Component {...props} onClick={handleClick} />;
};
};
// Использование
const AnalyticsButton = withAnalytics(SimpleButton);
В JavaScript/TypeScript (и особенно в Angular) есть специальный синтаксис декораторов через @.
@Component({ selector: 'app-root' })
class App {}
Суть та же: мы "навешиваем" на класс дополнительную логику (метаданные), не меняя код самого класса. React предпочитает функции-обертки (HOC), а Angular — синтаксис @.
Composite
Компоновщик — позволяет сгруппировать объекты в древовидную структуру и работать с этой структурой так же, как с одиночным объектом.
Дерево интерфейса
graph TD
Root[App Container]
Header[Header]
Main[Main Content]
Footer[Footer]
Root --> Header
Root --> Main
Root --> Footer
Main --> Sidebar
Main --> Feed
Feed --> Post1
Feed --> Post2
Это самый родной паттерн для веба. DOM-дерево браузера — это Composite. <div> может содержать другие <div> или текст. React-дерево — это Composite. Группы слоев в Figma — это Composite.
Web-way Reality: Рекурсивный рендеринг
Паттерн проявляется, когда нам нужно отрисовать вложенную структуру, не зная заранее глубины вложенности.
// Компонент, который может содержать сам себя
const Folder = ({ name, files }) => (
<div>
<span>📁 {name}</span>
<div style={{ paddingLeft: 20 }}>
{files.map(file =>
file.type === 'folder'
? <Folder key={file.name} {...file} /> // Рекурсия (Composite)
: <span key={file.name}>📄 {file.name}</span>
)}
</div>
</div>
);
Proxy
Заместитель — объект, который перехватывает вызовы к другому объекту. Это «секьюрити» на входе в клуб: он может не пустить (валидация), может что-то записать в журнал (логирование), а может просто передать запрос дальше.
Перехват доступа
sequenceDiagram
participant Client
participant Proxy
participant RealSubject as Real Data
Client->>Proxy: Request Data (get ID: 1)
Note over Proxy: Check Cache?
alt Cache hit
Proxy-->>Client: Return Cached Data
else Cache miss
Proxy->>RealSubject: Fetch Data
RealSubject-->>Proxy: Data
Proxy-->>Client: Data
end
JS Proxy и Реактивность
В современном JavaScript есть встроенный объект Proxy. Именно на нем построена реактивность во Vue 3 и MobX. Когда вы меняете свойство объекта, Proxy перехватывает это изменение и запускает перерисовку интерфейса.
const user = {
name: "Alice",
age: 25
};
// Создаем прокси для валидации
const secureUser = new Proxy(user, {
set(target, prop, value) {
if (prop === 'age' && typeof value !== 'number') {
console.error("Age must be a number!");
return false;
}
console.log(`Property ${prop} changed to ${value}`);
target[prop] = value;
return true;
}
});
secureUser.age = "text"; // Ошибка: Age must be a number!
secureUser.age = 26; // Лог: Property age changed to 26
Bridge
Мост — разделяет абстракцию (интерфейс) и реализацию, чтобы они могли изменяться независимо. Это паттерн для проектирования библиотек и кросс-платформенных решений.
Разделение UI и Платформы
graph TD
subgraph Abstraction ["UI Library"]
Button["Button Component"]
end
subgraph Implementation ["Renderer"]
Web["Web Renderer (DOM)"]
Mobile["Mobile Renderer (Native)"]
end
Button -.->|Uses| Web
Button -.->|Uses| Mobile
В веб-разработке чистый "Мост" встречается редко в бизнес-логике, но часто в архитектуре. Самый яркий пример — React. Сами компоненты React (Абстракция) не знают, где они будут отрисованы. За отрисовку отвечает react-dom или react-native.
Темы и UI Киты
Более приземленный пример — система темизации. Компонент «Кнопка» определяет логику (нажатие, состояние загрузки), но делегирует внешний вид текущей Теме.
Вы можете подменить тему (Implementation) со светлой на темную, не меняя код кнопки (Abstraction).
Facade
Фасад — простой интерфейс для сложной системы. Он скрывает за собой «магию» инициализации, зависимостей и сложной логики.
Скрытие сложности
graph LR
UI["Frontend Component"] --> Facade["API Service (Facade)"]
Facade --> Auth["Auth Module"]
Facade --> Http["Axios Config"]
Facade --> Cache["LocalStorage"]
Facade --> Error["Error Handler"]
API Service
Когда вы в компоненте вызываете метод buyProduct(id), вы используете Фасад. Вам не нужно знать, что внутри этой функции:
- Проверяется токен авторизации.
- Данные сериализуются в JSON.
- Делается запрос через Axios.
- Если ошибка 401 — делается refresh токена и повтор запроса.
- Результат кэшируется.
Для компонента это просто одна строка кода. Вся сложность скрыта в файле api.js или кастомном хуке useCheckout.
// Facade хук или сервис
class ApiFacade {
static async getUserProfile() {
// Скрытая сложная логика
const token = localStorage.getItem('token');
if (!token) throw new Error("No token");
const response = await fetch('/api/me', {
headers: { Authorization: `Bearer ${token}` }
});
return response.json();
}
}
// Клиентский код (просто и чисто)
const profile = await ApiFacade.getUserProfile();
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ