На практике я применял следующие паттерны проектирования:
Фабричный метод (Factory Method): Для создания объектов разных типов без указания конкретного класса создания. Удобно при работе с различными источниками данных или конфигурациями.
// Пример использования фабричного метода
class DataReader {
read() {
throw new Error("Method not implemented");
}
}
class FileReader extends DataReader {
read() {
console.log("Reading data from file...");
}
}
class NetworkReader extends DataReader {
read() {
console.log("Reading data from network...");
}
}
class DataReaderFactory {
createReader(type) {
switch (type) {
case "file":
return new FileReader();
case "network":
return new NetworkReader();
default:
throw new Error("Unknown reader type");
}
}
}
const factory = new DataReaderFactory();
const fileReader = factory.createReader("file");
fileReader.read();
Одиночка (Singleton): Для гарантии существования только одного экземпляра класса и предоставления глобальной точки доступа к нему. Часто используется для менеджеров конфигурации или подключений к базам данных.
// Пример использования одиночки
class ConfigManager {
constructor() {
if (ConfigManager.instance) {
return ConfigManager.instance;
}
this.config = {};
ConfigManager.instance = this;
}
setConfig(key, value) {
this.config[key] = value;
}
getConfig(key) {
return this.config[key];
}
}
const instance1 = new ConfigManager();
const instance2 = new ConfigManager();
console.log(instance1 === instance2); // true
Наблюдатель (Observer): Для реализации связи "один-ко-многим", где при изменении состояния одного объекта (издателя) автоматически оповещаются все зависимые объекты (подписчики). Используется в системах уведомлений, реактивных интерфейсах.
// Пример использования наблюдателя
class Observable {
constructor() {
this.observers = [];
}
subscribe(observer) {
this.observers.push(observer);
}
unsubscribe(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
notify(data) {
this.observers.forEach(observer => observer.update(data));
}
}
class Observer {
update(data) {
console.log("Received update:", data);
}
}
const observable = new Observable();
const observer1 = new Observer();
const observer2 = new Observer();
observable.subscribe(observer1);
observable.subscribe(observer2);
observable.notify("New data available!");
Стратегия (Strategy): Для определения семейства алгоритмов, инкапсуляции каждого из них и обеспечения их взаимозаменяемости. Позволяет алгоритму меняться независимо от клиентов, его использующих. Применяется для различных вариантов обработки данных или выполнения операций.
// Пример использования стратегии
class PaymentStrategy {
pay(amount) {
}
}
class CreditCardPayment extends PaymentStrategy {
pay(amount) {
console.log(`Paying ${amount} using Credit Card`);
}
}
class PayPalPayment extends PaymentStrategy {
pay(amount) {
console.log(`Paying ${amount} using PayPal`);
}
}
class PaymentContext {
setStrategy(strategy) {
this.strategy = strategy;
}
executePayment(amount) {
this.strategy.pay(amount);
}
}
const context = new PaymentContext();
context.setStrategy(new CreditCardPayment());
context.executePayment(100);
context.setStrategy(new PayPalPayment());
context.executePayment(50);
Декоратор (Decorator): Для динамического добавления новой функциональности объекту без изменения его структуры. Обертывает существующий объект, предоставляя тот же интерфейс, что и обернутый объект, но с добавленной функциональностью. Удобно для логгирования, валидации, кеширования.
// Пример использования декоратора
class Component {
operation() {
return "Basic Component";
}
}
class Decorator {
constructor(component) {
this.component = component;
}
operation() {
return this.component.operation();
}
}
class ConcreteDecoratorA extends Decorator {
operation() {
return `ConcreteDecoratorA(${super.operation()})`;
}
}
class ConcreteDecoratorB extends Decorator {
operation() {
return `ConcreteDecoratorB(${super.operation()})`;
}
}
const simple = new Component();
console.log(simple.operation());
const decoratorA = new ConcreteDecoratorA(simple);
console.log(decoratorA.operation());
const decoratorB = new ConcreteDecoratorB(decoratorA);
console.log(decoratorB.operation());
Модуль (Module): Хотя в Node.js система модулей встроена (CommonJS, ES Modules), паттерн Module pattern в JavaScript (до появления нативных модулей) использовался для создания приватных членов и публичного интерфейса. Это является основой для построения инкапсулированного кода.
Эти паттерны помогали мне создавать более структурированный, масштабируемый и поддерживаемый код.