CREATIONAL

Abstract Factory

Fornire un'interfaccia per creare famiglie di oggetti correlati senza specificare le loro classi concrete.

Il Problema

Quando devi creare famiglie di oggetti correlati che devono essere usati insieme (es. UI components per temi diversi), ma vuoi mantenere il codice indipendente dalle classi concrete.

La Soluzione

Dichiarare interfacce per ogni tipo di prodotto nella famiglia. Quindi dichiarare l'abstract factory con metodi per creare ogni tipo di prodotto. Implementare concrete factory per ogni variante della famiglia.

Struttura

AbstractFactory con metodi per creare AbstractProduct, ConcreteFactory che creano ConcreteProduct, e client che usa solo interfacce.

Partecipanti:
AbstractFactory - interfaccia per creare prodotti astratti
ConcreteFactory - implementa operazioni per creare prodotti concreti
AbstractProduct - interfaccia per un tipo di prodotto
ConcreteProduct - implementazione di un prodotto, creata da una ConcreteFactory
Esempi di Codice

Abstract Factory per UI Cross-Platform

Creazione di componenti UI per Windows e Mac.

TYPESCRIPT
// Abstract Products
interface Button {
  render(): void;
  onClick(callback: () => void): void;
}

interface Checkbox {
  render(): void;
  toggle(): void;
}

// Concrete Products - Windows
class WindowsButton implements Button {
  render(): void {
    console.log('Rendering Windows button');
  }
  onClick(callback: () => void): void {
    console.log('Windows button clicked');
    callback();
  }
}

class WindowsCheckbox implements Checkbox {
  render(): void {
    console.log('Rendering Windows checkbox');
  }
  toggle(): void {
    console.log('Windows checkbox toggled');
  }
}

// Concrete Products - Mac
class MacButton implements Button {
  render(): void {
    console.log('Rendering Mac button');
  }
  onClick(callback: () => void): void {
    console.log('Mac button clicked');
    callback();
  }
}

class MacCheckbox implements Checkbox {
  render(): void {
    console.log('Rendering Mac checkbox');
  }
  toggle(): void {
    console.log('Mac checkbox toggled');
  }
}

// Abstract Factory
interface GUIFactory {
  createButton(): Button;
  createCheckbox(): Checkbox;
}

// Concrete Factories
class WindowsFactory implements GUIFactory {
  createButton(): Button {
    return new WindowsButton();
  }
  createCheckbox(): Checkbox {
    return new WindowsCheckbox();
  }
}

class MacFactory implements GUIFactory {
  createButton(): Button {
    return new MacButton();
  }
  createCheckbox(): Checkbox {
    return new MacCheckbox();
  }
}

// Client code
function renderUI(factory: GUIFactory) {
  const button = factory.createButton();
  const checkbox = factory.createCheckbox();
  
  button.render();
  checkbox.render();
}

// Utilizzo
const os = 'Windows'; // oppure 'Mac'
const factory = os === 'Windows' ? new WindowsFactory() : new MacFactory();
renderUI(factory);
Esempi nel Mondo Reale
UI Toolkit - Componenti diversi per tema dark/light o piattaforma Windows/Mac/Linux
Database Access - Factory per creare Connection, Command, DataReader per DB diversi
Documenti multi-formato - Factory per creare elementi PDF, HTML, DOC
E-commerce - Factory per creare Payment, Shipping, Notification per diversi paesi
Game Development - Factory per creare Enemy, Weapon, PowerUp per livelli diversi
Quando Usarlo
Quando il sistema deve essere indipendente da come i prodotti sono creati
Quando il sistema deve funzionare con diverse famiglie di prodotti
Quando vuoi garantire che i prodotti di una famiglia siano usati insieme
Quando vuoi fornire una libreria di prodotti rivelando solo le interfacce
Quando NON Usarlo
Quando hai una sola famiglia di prodotti
Quando aggiungere nuovi tipi di prodotti è raro
Quando la gerarchia di factory diventa troppo complessa