Perché utilizzare una sottoclasse anziché composita quando si utilizza il modello di progettazione Metodo di fabbrica?

4

Attualmente sto imparando a conoscere i modelli di design. Ho imparato a conoscere il modello del metodo di fabbrica.

Questo modello significa che per implementare una fabbrica per creare oggetti, si dovrebbe sottoclasse la classe che ha bisogno di questi oggetti e la sottoclasse li creerà. In questo modo la superclasse funziona solo con riferimenti più astratti anziché con le implementazioni concrete che la sottoclasse genera, creando un design liberamente accoppiato.

Questo di solito significa che la superclasse diventa abstract , poiché il suo metodo createObject() deve essere abstract in modo che la sottoclasse contenente il metodo factory debba implementare questo metodo.

Come qualsiasi modello di fabbrica, questo modello incapsula la creazione dell'oggetto concreto e consente al client di lavorare con un livello più alto di astrazione. Ma questo modello specifico è costruito sull'eredità.

Ciò che non capisco è - Perché qualcuno dovrebbe affrontare tutti i problemi della sottoclasse della classe che ha bisogno di una fabbrica e che la rende abstract ? La composizione è molto migliore per questo scopo in qualsiasi modo.

Ha molto più senso creare una classe astratta o un'interfaccia chiamata Factory . Dichiarerebbe un metodo: createObject() . Noi creiamo implementazioni concrete di esso per scopi diversi ( WeaponFactory , TitleFactory ..) Quindi, forniamo al cliente un Factory istanza membro factory . Questo riferimento è impostato su qualsiasi cosa concreta Factory è necessaria al runtime e il client può semplicemente utilizzare factory 's createObject() quando necessario (senza dover sapere quale implementazione concreta factory è di mantenimento).

Non capisco perché si debba passare attraverso la difficoltà di sottoclassi di una classe e di renderla astratta solo per il vantaggio di consentirgli di utilizzare una fabbrica in modo non strettamente accoppiato.

Il semplice design basato sulla composizione che ho descritto è migliore in ogni caso, credo.

Sei d'accordo? Potresti spiegare perché qualcuno userebbe il modello di metodo di fabbrica che ho descritto?

    
posta Aviv Cohn 20.03.2014 - 01:52
fonte

3 risposte

3

Il Design Patterns libro è descrittivo , non prescrittivo ; descrive i modelli che il GoF ha osservato in natura; schemi che risolvono i problemi.

Alcuni problemi possono essere risolti in più di un modo.

L'alternativa che descrivi è anche il mio approccio preferito, ma è anche descritta nel libro: è una combinazione dei modelli Abstract Factory e Strategia . Usi una Fabbrica astratta come strategia.

I don't understand why one would go through the trouble of subclassing a class and making it abstract just for the benefit of allowing it to use a factory in a loosely-coupled manner.

Per la stessa identica ragione per cui combinerai Fabbrica e strategia astratte. Tuttavia, la soluzione migliore dipende in parte dalla tua lingua.

Se, ad esempio, stavi programmando a Eiffel, il metodo Factory sarebbe probabilmente più semplice, perché Eiffel ha ereditarietà multipla, ma (IIRC) nessuna interfaccia.

Inoltre, se stai utilizzando una lingua in cui puoi creare un valore derivato sul posto (come Java o F #), il metodo Factory potrebbe essere effettivamente più semplice della combinazione Abstract Factory / Strategy.

    
risposta data 20.03.2014 - 10:00
fonte
0

In generale sono d'accordo che la composizione sia meglio dell'eredità. I modelli di progettazione GOF sono fantastici perché probabilmente c'è il primo tentativo di costruire un linguaggio (i pattern sono un linguaggio per me) in un nuovo livello di astrazione, a livello di progettazione invece che a livello di programmazione, questo è grandioso, ma alcuni schemi concreti sono forse obsoleto o può essere migliorato per adattarsi alla situazione, alla tecnologia o alle preferenze concrete. Lo studio dei modelli è una buona cosa, può insegnarti alcuni buoni trucchi e tecniche OO, ma l'applicazione dei modelli "dal libro" non è mai una buona idea IMMO.

Comunque, vedo un problema con il tuo progetto, almeno un problema in un linguaggio tipizzato statico, armi di ritorno di WeaponFactory e titoli di ritorno titoloFactory suppongo, il tipo di ritorno per "createObject" è diverso e questo tipo di ritorno è parte del firma del metodo. Ma ovviamente con la composizione e il DI si possono raggiungere gli stessi obiettivi che il metodo di fabbrica cerca di raggiungere. Ad esempio:

Client clientWithRealWeapon = new Client(new RealWeaponsFactory());
Client clientWithMocksWeapon = new Client(new MockWeaponsFactory());

è una soluzione con composizione e DI, lo stesso può essere fatto creando due sottoclassi di client: ClientWithRealWeapons e ClientWithMocksWeapons che sovrascrivono un metodo per la creazione di armi.

    
risposta data 20.03.2014 - 02:21
fonte
0

Penso che tu stia esaminando il problema nel modo sbagliato. Se hai bisogno di creare una delle diverse sottoclassi, dovrai utilizzare il metodo Factory come lo hai descritto per risolvere il problema.

Ad esempio, se disponi di un sistema in cui è necessario che la maggior parte del codice sia la stessa, ma varia solo in alcuni dettagli, la sottoclasse ha un senso a sé stante e lo farai, quindi creerai le fabbriche che sono in grado di estrarre le sottoclassi corrette in base alle regole di cui ciascuna ha bisogno. Potresti anche avere un sistema legacy in cui le sottoclassi sono già in uso e scoprirai che mentre si ridimensiona vuoi aggiungere delle fabbriche per aiutarti nella creazione dei tuoi oggetti.

Se stai usando qualcosa come un sistema Entity e non hai bisogno di sottoclassi dell'oggetto Product, non crearlo affatto. Tuttavia, potresti voler assicurarti che la tua singola classe implementa almeno un'interfaccia, perché ogni tanto è necessario utilizzare un'implementazione completamente indipendente quando si ottiene un requisito che non si vede arrivare.

    
risposta data 20.03.2014 - 02:41
fonte