Factory-паттерн представляет собой архитектурный подход, при котором
создание объектов выносится в отдельную функцию или слой абстракции.
Вместо прямого использования конструктора или оператора new
код получает готовый объект через фабрику, которая инкапсулирует логику
выбора и конфигурации.
Ключевая особенность заключается в том, что фабрика не просто создаёт объект, а принимает решения о его конкретной реализации на основе входных параметров, окружения или состояния приложения.
Основные характеристики:
В контексте ECMAScript Internationalization API фабричный подход проявляется естественным образом, поскольку большинство его сущностей создаются через конструкторы с конфигурационными параметрами, формируя предсказуемые и переиспользуемые экземпляры форматирования.
Intl API в JavaScript предоставляет набор специализированных конструкторов, каждый из которых фактически реализует фабричную модель:
Intl.NumberFormatIntl.DateTimeFormatIntl.CollatorIntl.PluralRulesIntl.RelativeTimeFormatIntl.ListFormatКаждый из этих конструкторов не просто создаёт объект, а формирует конфигурированный форматтер, адаптированный под локаль и правила языка.
const formatter = new Intl.NumberFormat('ru-RU', {
style: 'currency',
currency: 'RUB'
});
formatter.format(123456.78); // "123 456,78 ₽"
Здесь Intl.NumberFormat выступает фабрикой, которая на
основании параметров возвращает объект форматирования, скрывающий
внутреннюю логику локализации чисел.
Factory-паттерн особенно заметен в работе с числами, поскольку форматирование зависит от множества факторов:
Фабричный подход позволяет инкапсулировать эти параметры:
function createCurrencyFormatter(locale, currency) {
return new Intl.NumberFormat(locale, {
style: 'currency',
currency
});
}
const usdFormatter = createCurrencyFormatter('en-US', 'USD');
const eurFormatter = createCurrencyFormatter('de-DE', 'EUR');
Такая функция-фабрика устраняет дублирование конфигурации и централизует логику создания форматтеров.
Intl.DateTimeFormat демонстрирует ещё более яркое
применение фабричной модели, поскольку форматирование дат зависит от
культурных и региональных соглашений.
const ruFormatter = new Intl.DateTimeFormat('ru-RU', {
dateStyle: 'full',
timeStyle: 'short'
});
const jpFormatter = new Intl.DateTimeFormat('ja-JP', {
dateStyle: 'long'
});
Каждый вызов конструктора возвращает специализированный объект, который уже содержит всю необходимую информацию для преобразования даты.
Фабричный характер проявляется в том, что:
Intl.Collator предоставляет механизм сравнения строк с
учётом языковых правил. Это один из наиболее показательных примеров
фабрики в Intl API.
const collator = new Intl.Collator('ru', {
sensitivity: 'base'
});
['ё', 'е', 'ж'].sort(collator.compare);
Метод compare является результатом фабричной
конфигурации, где:
Фактически Intl.Collator возвращает не просто объект, а
стратегию сравнения строк, что соответствует расширенному варианту
Factory-паттерна — фабрике стратегий.
Использование фабрик поверх Intl API позволяет формировать архитектурно чистые слои локализации.
const formattersFactory = {
number(locale) {
return new Intl.NumberFormat(locale);
},
currency(locale, currency) {
return new Intl.NumberFormat(locale, {
style: 'currency',
currency
});
},
date(locale, options) {
return new Intl.DateTimeFormat(locale, options);
}
};
Такой подход позволяет централизовать создание всех форматтеров и управлять ими из одного места.
Intl объекты являются тяжёлыми в создании при массовом использовании, поэтому фабричный слой часто дополняется кэшированием.
const cache = new Map();
function getNumberFormatter(locale, options) {
const key = JSON.stringify({ locale, options });
if (cache.has(key)) {
return cache.get(key);
}
const formatter = new Intl.NumberFormat(locale, options);
cache.set(key, formatter);
return formatter;
}
Такой подход:
В реальных приложениях фабрика часто служит промежуточным слоем между системой и пользовательскими настройками.
function createAppFormatters(userSettings) {
const locale = userSettings.locale || 'en-US';
return {
price: new Intl.NumberFormat(locale, {
style: 'currency',
currency: userSettings.currency
}),
date: new Intl.DateTimeFormat(locale, {
dateStyle: 'medium'
}),
list: new Intl.ListFormat(locale, {
style: 'long',
type: 'conjunction'
})
};
}
Такой слой позволяет:
Intl.PluralRules и Intl.RelativeTimeFormat
расширяют фабричную концепцию за счёт генерации вычислительных
стратегий.
const pluralRules = new Intl.PluralRules('ru-RU');
pluralRules.select(5); // "many"
const rtf = new Intl.RelativeTimeFormat('ru', { numeric: 'auto' });
rtf.format(-1, 'day'); // "вчера"
Здесь фабрика создаёт объект, который:
Factory-паттерн в связке с Intl API часто комбинируется с другими архитектурными подходами:
Пример композиции:
class LocalizationService {
constructor(locale) {
this.locale = locale;
this.number = new Intl.NumberFormat(locale);
this.date = new Intl.DateTimeFormat(locale);
this.list = new Intl.ListFormat(locale);
}
formatPrice(value, currency) {
return new Intl.NumberFormat(this.locale, {
style: 'currency',
currency
}).format(value);
}
}
Неправильное применение фабрик часто приводит к избыточной сложности:
Особенно критичной становится ситуация, когда фабрика используется как простая обёртка без переиспользования экземпляров, что приводит к лишним затратам на инициализацию.
Intl объекты оптимизированы для повторного использования, поэтому фабричный слой должен учитывать:
Типичная оптимизация:
const numberFormatter = new Intl.NumberFormat('ru-RU');
function format(value) {
return numberFormatter.format(value);
}
Такой подход снижает накладные расходы и сохраняет архитектурную чистоту.
В крупных приложениях фабричный слой над Intl API становится центральным элементом системы локализации. Он обеспечивает:
Фабричная модель превращает Intl API из набора отдельных инструментов в структурированную систему генерации локализованных представлений данных.