Singleton
Одиночка — паттерн, гарантирующий, что у класса есть только один экземпляр, и предоставляющий к нему глобальную точку доступа.
Глобальный доступ к состоянию
graph TD
ClientA[Component A] --> Singleton((Store / Service))
ClientB[Component B] --> Singleton
ClientC[Component C] --> Singleton
В мире Java/C++ для этого нужно писать специальные методы getInstance() и блокировать потоки. В JavaScript всё намного проще и элегантнее.
Сам механизм ES-модулей (import/export) работает как Синглтон. Когда вы импортируете объект из файла, среда выполнения (Node.js или бандлер вроде Webpack) выполняет файл один раз, кэширует результат и отдает одну и ту же ссылку всем, кто делает import.
API Service и Store
Классический пример — сервис для работы с API или глобальное хранилище (Store). Нам не нужно создавать новый объект подключения к серверу в каждой кнопке.
// apiService.js
class ApiService {
constructor() {
this.baseUrl = 'https://api.example.com';
}
fetchData() {
console.log('Fetching from ' + this.baseUrl);
}
}
// Создаем экземпляр СРАЗУ при экспорте
const apiInstance = new ApiService();
// Экспортируем уже готовый объект (Singleton)
export default apiInstance;
// component1.js
import api from './apiService'; // Получаем ссылку #123
// component2.js
import api from './apiService'; // Получаем ту же ссылку #123
Плюсы:
- Экономия памяти (один объект вместо тысяч).
- Общее состояние (если вы измените настройки в одном месте, они изменятся везде).
Минусы:
- Тесты могут влиять друг на друга, так как состояние общее. Приходится писать методы для "сброса" синглтона.
- В JS "одиночка" живет, пока не перезагрузится страница.
3.2 Factory [Method]
Фабричный метод — определяет интерфейс для создания объекта, но позволяет подклассам (или условиям) решать, какой именно класс создавать.
Фабрика компонентов
flowchart LR
Input[Data Type: 'date'] --> Factory{Component Factory}
Input2[Data Type: 'text'] --> Factory
Factory --> DatePicker[< DatePicker />]
Factory --> TextInput[< TextInput />]
Во Frontend мы редко используем наследование классов для фабрик. Вместо этого мы используем функции-фабрики, которые возвращают разные React-компоненты или объекты конфигурации в зависимости от входных данных (props).
Динамические формы
Представьте, что вы строите форму по JSON-конфигу с бэкенда. Вам приходит поле type: "checkbox" или type: "select". Вы не знаете заранее, какие поля будут.
// "Фабрика" полей формы
const FieldFactory = (props) => {
switch (props.type) {
case 'text':
return <input type="text" {...props} />;
case 'checkbox':
return <input type="checkbox" checked={props.value} />;
case 'date':
return <DatePicker date={props.value} />;
default:
return null;
}
};
// Использование
// Мы просто говорим "дай мне поле типа date", не думая о реализации
const App = () => (
<div>
<FieldFactory type="text" placeholder="Name" />
<FieldFactory type="date" />
</div>
);
Abstract Factory
Абстрактная фабрика — создает семейства взаимосвязанных объектов. Это "Фабрика фабрик".
Семейства тем Design Systems
classDiagram
class AbstractThemeFactory {
<<interface>>
+createButton()
+createInput()
}
class DarkThemeFactory {
+createButton() // Returns DarkButton
+createInput() // Returns DarkInput
}
class LightThemeFactory {
+createButton() // Returns LightButton
+createInput() // Returns LightInput
}
AbstractThemeFactory <|.. DarkThemeFactory
AbstractThemeFactory <|.. LightThemeFactory
Если обычная Фабрика создает один объект (Кнопку), то Абстрактная Фабрика создает стиль (Кнопку, Инпут, Чекбокс), которые гарантированно сочетаются друг с другом.
В React это часто реализуется через библиотеку компонентов (MUI, AntD) или через Theme Context.
Кросс-платформенная разработка
В React Native это критически важно. У вас есть абстракция AlertFactory. На iOS она должна вызывать AlertIOS, на Android — ToastAndroid, а в вебе — window.alert или красивую модалку.
// Абстракция использования (клиентский код одинаковый)
const showNotification = (factory, message) => {
const notification = factory.createNotification();
notification.show(message);
}
// Семейство Web
const WebFactory = {
createNotification: () => ({ show: (msg) => alert(msg) })
};
// Семейство Mobile (условно)
const MobileFactory = {
createNotification: () => ({ show: (msg) => Vibration.vibrate() })
};
Prototype
Прототип — создает новые объекты путем клонирования существующего (прототипа), вместо создания с нуля через конструктор.
Клонирование состояния
graph LR
Original[Default Config Object] -- "Clone & Modify" --> UserConfig[User Config Object]
UserConfig -- "Clone & Modify" --> SessionConfig[Session Config]
JavaScript — это прототипный язык. Здесь всё построено на этом паттерне. Но в современной разработке (особенно в Redux/React) мы используем этот паттерн для Иммутабельности (Immutability).
Мы не меняем существующий объект (чтобы не сломать ре-рендеры), мы берем его как прототип, клонируем и меняем только нужное поле.
Spread Operator
Вместо сложного метода obj.clone(), мы используем Spread-оператор (...) или structuredClone().
const defaultSettings = {
theme: 'light',
notifications: true,
volume: 50
};
// Паттерн Прототип в действии:
// Берем defaultSettings как основу (прототип) и создаем новый объект,
// переопределяя только theme.
const userSettings = {
...defaultSettings,
theme: 'dark'
};
console.log(userSettings.volume); // 50 (скопировано из прототипа)
Это основа работы Redux-редьюсеров и хука useState в React при работе с объектами.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ