Il problema: oggetti che devono essere coerenti tra loro
Immagina un'applicazione che genera documenti in formati diversi: PDF e HTML. Un documento PDF ha un PdfHeader, un PdfParagraph e un PdfTable. Un documento HTML ha un HtmlHeader, un HtmlParagraph e un HtmlTable. Il problema non e creare i singoli componenti — e assicurarsi che non vengano mai mescolati. Un PdfHeader con un HtmlTable nello stesso documento e un bug silenzioso che si manifesta solo in produzione.
Con il Factory Method crei un singolo oggetto alla volta. Ma quando servono famiglie di oggetti che devono essere coerenti tra loro — tutti PDF o tutti HTML, mai misti — serve un livello di astrazione superiore. L'Abstract Factory risolve esattamente questo: garantisce che una famiglia di oggetti correlati venga creata come un insieme coerente.
Cos'e l'Abstract Factory: definizione formale
Il Gang of Four definisce l'Abstract Factory come un pattern creazionale che "fornisce un'interfaccia per creare famiglie di oggetti correlati o dipendenti senza specificare le loro classi concrete". La struttura prevede:
-
AbstractFactory: l'interfaccia che dichiara i metodi di creazione per ogni tipo di prodotto (
createHeader(),createParagraph(),createTable()) -
ConcreteFactory: ogni factory crea una famiglia specifica (
PdfDocumentFactory,HtmlDocumentFactory) -
AbstractProduct: l'interfaccia per ogni tipo di prodotto (
HeaderInterface,ParagraphInterface) -
ConcreteProduct: le implementazioni specifiche (
PdfHeader,HtmlHeader)
Il client riceve una factory nel costruttore e chiama i metodi di creazione. Non sa se sta creando componenti PDF o HTML — sa solo che sono coerenti tra loro perché vengono dalla stessa factory.
Esempio teorico: un sistema di UI multi-tema
Un'applicazione web offre due temi: Light e Dark. Ogni tema ha i propri componenti: Button, Input, Card, Modal. I componenti di un tema hanno stili, colori e comportamenti diversi ma implementano la stessa interfaccia.
-
ThemeFactoryInterfacedichiara:createButton(): ButtonInterface,createInput(): InputInterface,createCard(): CardInterface -
LightThemeFactorycreaLightButton,LightInput,LightCard— tutti con sfondo chiaro e testo scuro -
DarkThemeFactorycreaDarkButton,DarkInput,DarkCard— tutti con sfondo scuro e testo chiaro
Il page builder riceve un ThemeFactoryInterface e costruisce la pagina senza sapere quale tema sta usando. Cambiare tema richiede una sola modifica: quale factory viene iniettata. Nessun componente viene mai mescolato tra temi diversi.
Esempio teorico: driver di database
Un ORM deve creare oggetti diversi per MySQL e PostgreSQL: query builder, schema builder, migrator. Ogni driver ha le proprie implementazioni con sintassi SQL diversa. L'AbstractDatabaseFactory dichiara createQueryBuilder(), createSchemaBuilder(), createMigrator(). La MysqlFactory crea componenti MySQL, la PgsqlFactory crea componenti PostgreSQL. Il codice di migrazione non sa su quale database sta operando.
In Soft PHP MVC, il SchemaGrammarFactory::createFromEnv() e un esempio pratico di questo concetto: crea la grammar corretta in base al driver configurato nell'environment, garantendo che tutte le operazioni SQL usino la sintassi giusta per il database in uso.
Abstract Factory vs Factory Method
- Factory Method: crea un oggetto. Un metodo, un prodotto. La sottoclasse decide quale implementazione concreta creare.
- Abstract Factory: crea una famiglia di oggetti correlati. Più metodi, più prodotti, tutti coerenti. La factory concreta garantisce la coerenza.
Se hai bisogno di un solo tipo di oggetto, usa Factory Method. Se hai bisogno di più oggetti che devono essere coerenti tra loro, usa Abstract Factory. Spesso un'Abstract Factory usa internamente Factory Method per creare i singoli prodotti.
Quando usare l'Abstract Factory
- Usa l'Abstract Factory quando il sistema deve creare famiglie di oggetti correlati che non devono mai essere mescolati
- Usa l'Abstract Factory quando vuoi fornire una libreria di prodotti senza esporre le implementazioni concrete
- Usa l'Abstract Factory quando il sistema deve supportare più piattaforme, temi o driver con componenti diversi
- Non usare l'Abstract Factory se crei un solo tipo di oggetto: e overkill, usa Factory Method
- Non usare l'Abstract Factory se le famiglie non cambiano mai: la flessibilita ha un costo di complessità
L'Abstract Factory e il pattern della coerenza garantita. In un mondo dove i sistemi supportano multipli driver, temi, formati e piattaforme, garantire che i componenti di una famiglia non vengano mai mescolati e un requisito architetturale, non un lusso.
Top comments (0)