Что такое "фабрика" в программировании? На примере JavaScript
-
Фабрика (Factory) — это паттерн проектирования, который позволяет создавать объекты без указания конкретного класса или типа. Вместо прямого вызова
new SomeClass()
, ты используешь функцию (или объект), которая решает, какой именно объект создать, в зависимости от входных данных.Преимущества:
- Упрощает расширение кода.
- Скрывает сложность создания объектов.
- Централизует логику создания.
Пример: Фабрика на JavaScript
Допустим, у нас есть разные типы пользователей: админ, модератор, обычный пользователь. У каждого разные права.
Мы можем создать фабрику, которая будет возвращать нужный объект в зависимости от роли.
// Базовый класс пользователя class User { constructor(name, role) { this.name = name; this.role = role; } getInfo() { return `${this.name} — ${this.role}`; } hasAccess() { return false; } } // Конкретные типы пользователей class Admin extends User { constructor(name) { super(name, 'admin'); } hasAccess() { return true; // Админ имеет доступ ко всему } deleteAccount(userId) { console.log(`Админ ${this.name} удалил аккаунт ${userId}`); } } class Moderator extends User { constructor(name) { super(name, 'moderator'); } hasAccess() { return true; } banUser(userId) { console.log(`Модератор ${this.name} забанил пользователя ${userId}`); } } class RegularUser extends User { constructor(name) { super(name, 'user'); } hasAccess() { return false; } } // 🏭 Фабрика пользователей function createUser(name, role) { switch (role) { case 'admin': return new Admin(name); case 'moderator': return new Moderator(name); case 'user': return new RegularUser(name); default: throw new Error(`Неизвестная роль: ${role}`); } } // 🔧 Использование фабрики const admin = createUser("Алексей", "admin"); const mod = createUser("Мария", "moderator"); const user = createUser("Иван", "user"); console.log(admin.getInfo()); // Алексей — admin console.log(mod.getInfo()); // Мария — moderator console.log(user.getInfo()); // Иван — user console.log(admin.hasAccess()); // true console.log(user.hasAccess()); // false admin.deleteAccount(123); // Алексей удалил аккаунт 123 mod.banUser(456); // Мария забанила пользователя 456
Почему это удобно?
- Если ты захочешь добавить новый тип пользователя (например,
guest
), тебе нужно только:- Создать новый класс.
- Добавить его в
createUser
.
- Всё остальное приложение продолжает работать, используя общий интерфейс (
hasAccess
,getInfo
и т.д.).
Фабрика — это как “конвейер”, который на вход получает параметры (например,
role
) и на выходе даёт готовый объект нужного типа.Это делает код:
- гибче,
- легче для тестирования,
- проще для расширения.
-
А если нужно добавить новую роль, например, ‘editor’, не придется ли переписывать всю фабрику? Мне кажется, switch-конструкция не очень масштабируема.
-
Думаю, что можно заменить switch на объект-маппинг: const roles = { admin: Admin, moderator: Moderator } и потом вызывать new rolesrole. Так добавление новой роли будет в одну строку.
-
А как быть с зависимостями? Допустим, для создания Admin нужен дополнительный параметр — уровень доступа. Не усложнит ли это фабрику?
-
фабрика как раз для того и нужна, чтобы инкапсулировать сложную логику создания. Можно передавать объект с опциями: createUser({ name: ‘Alex’, role: ‘admin’, accessLevel: 3 }).
-
Не нарушает ли фабрика принципы SOLID? Вроде как должна быть открытость для расширения, но закрытость для изменений.
-
Если использовать маппинг через объект и не нарушает. Добавляешь новый класс и регистрируешь его в маппинге без изменения кода фабрики. Или можно вообще использовать внедрение зависимостей.
-
А я не могу понять, а как тестировать такие фабрики? Мокировать же все классы при unit-тестах? Будет результат? Что скажете?
-
Достаточно тестировать, что фабрика возвращает корректный тип объекта для разных входных параметров. А методы самих классов тестируются отдельно.
-
Теперь вижу, что фабрика действительно упрощает жизнь, особенно когда классов много. Попробую переделать свой модуль аутентификации по этому принципу.
© 2024 - 2025 ExLends, Inc. Все права защищены.