Perché ShapeFactory utilizza istruzioni condizionali per determinare quale oggetto istanziare. Non dobbiamo modificare ShapeFactory se vogliamo aggiungere altre classi in futuro? Perché questo non viola il principio di open closed?
La saggezza orientata agli oggetti convenzionale consiste nell'evitare le dichiarazioni if
e sostituirle con l'invio dinamico di metodi sovrascritti in sottoclassi di una classe astratta. Fin qui, tutto bene.
Ma il punto del pattern factory è che ti solleva dal dover conoscere le singole sottoclassi e lavorare solo con la superclasse astratta . L'idea è che la fabbrica sappia meglio di te quale classe specifica istanziare, e starai meglio lavorando solo con i metodi pubblicati dalla super classe. Questo è spesso vero e uno schema valido.
Pertanto, non c'è modo che la scrittura di una classe factory possa rinunciare alle dichiarazioni if
. Sposterebbe l'onere di scegliere una classe specifica per il chiamante, che è esattamente ciò che il modello dovrebbe evitare. Non tutti i principi sono assoluti (in effetti, il principio no è assoluto) e se si utilizza questo modello, si presume che il vantaggio sia maggiore del vantaggio di non utilizzare un if
.
L'esempio utilizza probabilmente un'istruzione condizionale perché è la più semplice. Un'implementazione più complessa potrebbe utilizzare una mappa o configurazione o (se si vuole essere davvero fantasiosi) una sorta di registro in cui le classi possono registrarsi. Tuttavia non c'è niente di sbagliato nell'usare un condizionale se il numero di classi è piccolo e cambia raramente.
Estendere il condizionale per aggiungere il supporto per una nuova sottoclasse in futuro sarebbe in effetti una violazione del principio aperto / chiuso. La soluzione "corretta" sarebbe quella di creare un nuovo stabilimento con la stessa interfaccia. Detto questo, l'aderenza al principio O / C deve essere sempre valutata rispetto ad altri principi di progettazione come KISS e YAGNI.
Detto questo, il codice visualizzato è chiaramente un codice di esempio che è stato progettato per mostrare il concetto di una fabbrica e nient'altro. Per esempio. è davvero un pessimo stile restituire null come fa l'esempio, ma una gestione degli errori più elaborata non farebbe altro che oscurare il punto. Il codice di esempio non è un codice di qualità di produzione, non devi aspettarti che lo sia.
Se parli del pattern Abstract Factory, il processo decisionale spesso non è nella Factory stessa ma nel codice dell'applicazione. È quel codice che sceglie quale fabbrica concreta istanziare e passare al codice cliente che utilizzerà gli oggetti prodotti dalla fabbrica. Guarda la fine dell'esempio Java qui: link
Il processo decisionale non implica necessariamente dichiarazioni if
. Potrebbe leggere il tipo di fabbrica concreto da un file di configurazione, derivarlo da una struttura di mappa, ecc.
Se pensi a Open-Close a livello di classe con questo factory stai facendo un'altra classe nel tuo sistema Open-Close, per esempio se hai un'altra classe che prende una Shape e calcola l'area (esempio tipico) questa classe è OpenClose perché può calcolare l'area per nuovi tipi di forme senza modifiche. Poi hai un'altra classe che disegna la forma, un'altra classe che prende N forme e restituisce quella più grande e puoi pensare in generale che le altre classi nel tuo sistema che si occupano di forme siano Open-Close (almeno sulle forme). Osservando il design, la fabbrica consente al resto del sistema di essere Open-Close e, naturalmente, la fabbrica stessa NON è Open-Close.
Ovviamente è possibile rendere questo factory anche open-close, tramite una sorta di caricamento dinamico e l'intero sistema può essere Open-Close (è possibile aggiungere nuove forme lasciando cadere alcuni jar nel classpath per esempio). È necessario valutare se questa complessità extra valga a seconda del sistema che stai costruendo, non tutti i sistemi necessitano di funzionalità collegabili e non tutto il sistema deve essere completamente Open-Close.
Dipende tutto da come lo si implementa. Puoi utilizzare std::map
per mantenere i puntatori di funzione alle funzioni che creano oggetti. Quindi il principio di apertura / chiusura non viene violato. O cambiare / caso.
Ad ogni modo, se non ti piace lo schema di fabbrica, puoi sempre usare l'iniezione di dipendenza.
Leggi altre domande sui tag design design-patterns factory factory-method