Коротка відповідь
middleAbstract Factory — це фабричний паттерн, що створює сімейства пов’язаних об’єктів без вказування їх конкретних класів. У TS це реалізується через інтерфейси фабрик і продуктів, а клієнт отримує об’єкти через абстрактний інтерфейс: `const factory = new ConcreteFactory(); const productA = factory.createProductA();`
Повне пояснення
1. Що це і навіщо
Абстрактна фабрика (Abstract Factory) – паттерн створення, що дозволяє генерувати пов’язані або залежні об’єкти без прив’язки до їх конкретних класів. Він знаходиться у розділі «Factory Method» GoF і використовується, коли система повинна працювати з різними сімействами продуктів (наприклад, UI‑компоненти для Windows і macOS).
2. Принцип роботи / алгоритм
Паттерн передбачає два рівні фабрик: AbstractFactory (інтерфейс) і конкретні реалізації, що повертають об’єкти AbstractProduct. Клієнт працює лише з інтерфейсами, не знаючи про конкретні класи. Діаграма: Client → AbstractFactory → ConcreteFactory → createProductX() → ConcreteProductX.
3. Реалізація (JS / TS)
- Базова реалізація
interface Button { render(): void; }
class WinButton implements Button{ render(){ console.log('Win button'); }}
class MacButton implements Button{ render(){ console.log('Mac button'); }}
interface GUIFactory { createButton(): Button; }
class WinFactory implements GUIFactory{ createButton(){ return new WinButton(); }}
class MacFactory implements GUIFactory{ createButton(){ return new MacButton(); }}
const factory:GUIFactory = process.platform==='win32'?new WinFactory():new MacFactory();
const btn=factory.createButton(); btn.render();
- Реалістичний приклад – створення різних типів API‑клієнтів (REST, GraphQL) через фабрику.
interface ApiClient{ request(url:string): Promise<any>; }
class RestClient implements ApiClient{ async request(url){ return fetch(url); }}
class GraphqlClient implements ApiClient{ async request(query){ /* gql */ } }
interface ClientFactory{ create(): ApiClient; }
class RestFactory implements ClientFactory{ create(){ return new RestClient(); }}
class GraphqlFactory implements ClientFactory{ create(){ return new GraphqlClient(); }}
- Спрощений для новачка – фабрика створює різні логери.
interface Logger{ log(msg:string): void; }
class ConsoleLogger implements Logger{ log(msg){ console.log(msg); }}
class FileLogger implements Logger{ log(msg){ /* write to file */ }}
interface LoggerFactory{ create(): Logger; }
class ConsoleLoggerFactory implements LoggerFactory{ create(){ return new ConsoleLogger(); }}
4. Тестування (Jest або Vitest)
import { WinFactory, MacFactory } from './factory';
describe('Abstract Factory', () => {
test('creates correct button for platform', () => {
const factory = process.platform==='win32'?new WinFactory():new MacFactory();
const btn = factory.createButton();
expect(btn.render).toBeInstanceOf(Function);
});
});
5. Проблеми та edge cases
- Неправильне використання ролей – клієнт залежить від конкретної фабрики, порушуючи інкапсуляцію.
- Зайва абстракція – коли сімейства продуктів не мають спільних властивостей, фабрика лише збільшує складність.
- Cyclical dependencies – фабрики можуть залежати одна від одної, створюючи циклічні імпорти.
- Плутанина між паттернами – часто плутають Abstract Factory з Factory Method; перший створює сімейства, другий – окремі об’єкти.
- Performance‑пастки – створення великої кількості фабрик у циклі може бути дорогим; краще кешувати інстанси.
6. Оптимізація та продуктивність
Фабрика додає один рівень абстракції, що незначно збільшує час створення об’єкта. Пам’ять витрачається лише на реальні інстанси продуктів; фабрика сама не зберігає стан. Для масштабованих систем можна використовувати паттерн Singleton для фабрик, щоб уникнути зайвих створень.
7. Без JS / архітектурні альтернативи
У чистій HTML/CSS можна розділити стилі за темами (Windows, macOS) через CSS‑перемінні або клас theme. У React можна створити контекст ThemeContext, що надає відповідні компоненти, замість фабрики.
8. Cheatsheet + follow-up
- Cheatsheet:
AbstractFactory → ConcreteFactory → createProductX() → ConcreteProductX. Клієнт не знає про конкретні класи. - Interview Q1: Як Abstract Factory відрізняється від Factory Method?
- Interview Q2: Які переваги має використання фабрики для створення UI‑компонентів різних платформ?