Jakie wzorce projektowe stosowałeś w praktyce?
sobes.tech AI
Odpowiedź od AI
W praktyce stosowałem następujące wzorce projektowe:
-
Metoda Fabryczna (Factory Method): Do tworzenia obiektów różnych typów bez wskazywania konkretnej klasy tworzącej. Przydatne przy pracy z różnymi źródłami danych lub konfiguracjami.
// Przykład użycia metody fabrycznej class DataReader { read() { throw new Error("Method not implemented"); } } class FileReader extends DataReader { read() { console.log("Odczyt danych z pliku..."); } } class NetworkReader extends DataReader { read() { console.log("Odczyt danych z sieci..."); } } class DataReaderFactory { createReader(type) { switch (type) { case "file": return new FileReader(); case "network": return new NetworkReader(); default: throw new Error("Nieznany typ czytnika"); } } } const factory = new DataReaderFactory(); const fileReader = factory.createReader("file"); fileReader.read(); -
Singleton (Singleton): Gwarantuje istnienie tylko jednej instancji klasy i zapewnia globalny dostęp do niej. Często używany do menedżerów konfiguracji lub połączeń z bazami danych.
// Przykład użycia singletona 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 -
Obserwator (Observer): Do implementacji relacji "jeden-do-wielu", gdzie przy zmianie stanu jednego obiektu (wydawcy) automatycznie powiadamiane są wszystkie zależne obiekty (subskrybenci). Używany w systemach powiadomień, reaktywnych interfejsach.
// Przykład użycia obserwatora 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("Otrzymano aktualizację:", data); } } const observable = new Observable(); const observer1 = new Observer(); const observer2 = new Observer(); observable.subscribe(observer1); observable.subscribe(observer2); observable.notify("Nowe dane dostępne!"); -
Strategia (Strategy): Do określenia rodziny algorytmów, enkapsulacji każdego z nich i zapewnienia ich wymienności. Pozwala na zmianę algorytmu niezależnie od klientów go używających. Używany do różnych wariantów przetwarzania danych lub wykonywania operacji.
// Przykład użycia strategii class PaymentStrategy { pay(amount) { throw new Error("Method not implemented"); } } class CreditCardPayment extends PaymentStrategy { pay(amount) { console.log(`Płacenie ${amount} kartą kredytową`); } } class PayPalPayment extends PaymentStrategy { pay(amount) { console.log(`Płacenie ${amount} przez 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); -
Dekorator (Decorator): Do dynamicznego dodawania nowej funkcjonalności obiektowi bez zmiany jego struktury. Opakowuje istniejący obiekt, zapewniając ten sam interfejs co opakowany, ale z dodaną funkcjonalnością. Przydatny do logowania, walidacji, buforowania.
// Przykład użycia dekoratora class Component { operation() { return "Podstawowy komponent"; } } 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()); -
Moduł (Module): Chociaż w Node.js system modułów jest wbudowany (CommonJS, ES Modules), wzorzec Module pattern w JavaScript (przed pojawieniem się natywnych modułów) był używany do tworzenia członków prywatnych i publicznego interfejsu. Stanowi podstawę do budowania enkapsulowanego kodu.
Te wzorce pomogły mi tworzyć bardziej strukturalny, skalowalny i łatwy do utrzymania kod.