Come sappiamo che favorire la composizione sulla generalizzazione è sempre la scelta giusta?

9

Se un oggetto esiste fisicamente o no, possiamo scegliere di modellarlo in modi diversi. In molti casi potremmo abusivamente usare la generalizzazione o la composizione. Tuttavia, il principio GoF di "favorire la composizione sulla generalizzazione [sic]" ci guida a usare la composizione. Quindi, quando modelliamo, per esempio, una linea, creiamo una classe che contiene due membri PuntoA e PuntoB del tipo Punto (composizione) invece di Estendere Punto (generalizzazione). Questo è solo un esempio semplificato di come possiamo arbitrariamente scegliere la composizione o l'ereditarietà da modellare, nonostante che gli oggetti siano di solito molto più complessi.

Come sappiamo che questa è la scelta giusta? Importa almeno perché potrebbe esserci un sacco di refactoring da fare se è sbagliato?

    
posta CarneyCode 10.04.2011 - 13:20
fonte

5 risposte

17

Non è sempre la scelta giusta. È favorevole nella maggior parte dei casi. Quando un modello composito richiede cambiamenti o estensioni, è notevolmente più resistente a questo perché è possibile modificare la composizione senza timore di influenzare inavvertitamente altre classi.

Come lo sappiamo? Dall'esperienza e dall'esperienza degli altri.

Ho visto molte situazioni in cui una massiccia gerarchia di classi è cresciuta da ciò che è iniziato come un concetto semplice, ed è qui che il tuo importante refactoring diventa necessario. Nel frattempo non ho mai visto una situazione in cui una struttura compositiva necessitasse di refactoring in ereditarietà.

Ma le mie prove aneddotiche non dovrebbero essere sufficienti. Basta guardare in internet e un buon numero di persone ha avuto le stesse esperienze.

    
risposta data 10.04.2011 - 14:30
fonte
7

Se vuoi una regola empirica più solida oltre "Favorisci la composizione sull'ereditarietà", allora potrei suggerire qualcosa del genere:

Dei due modi per specializzare un oggetto - Ereditarietà e composizione - dovresti usa l'ereditarietà solo quando hai bisogno che il tuo oggetto sia polimorfico (sostituibile) per la classe base che stai specializzando.

Tuttavia, come tutte le regole pratiche, una volta compresa la regola, sei libero di infrangere la regola:)

    
risposta data 10.04.2011 - 19:41
fonte
0

Non vedo come la composizione e la generalizzazione siano alternative e non è riuscito a trovare il citazione .
La composizione e l'ereditarietà sono (per conseguire la specializzazione), e si può argomentare, che astrazione e generalizzazione sono (per ottenere la modularità).

Quello che vuoi è che il tuo progetto sia semplice e plausibile, che sono due qualità che sono intrinsecamente facilmente misurabili.
Nel tuo caso, sembra più plausibile comporre una linea di due punti invece di estenderla, perché definiresti naturalmente una linea con due punti, piuttosto che estendendo il concetto di punto.

    
risposta data 10.04.2011 - 14:44
fonte
0

Il favore accade quando entrambi i candidati si qualificano. Il problema indicato nella domanda non riesce su questo account, perché ha solo un'opzione di composizione.

"Anche la composizione potrebbe usare la generalizzazione". Questa affermazione ha senso per noi? Altrimenti, non siamo ancora pronti ad afferrare la regola del "favore".

Perché stiamo favorendo la composizione è che la composizione offre più possibilità di estensione / flessibilità rispetto alla generalizzazione. Questa estensione / flessibilità si riferisce principalmente alla runtime / flessibilità dinamica (che si ottiene con la combinazione di interfacce e composizione).

Il vantaggio non è immediatamente visibile. Per vedere il vantaggio è necessario attendere la successiva richiesta di modifica imprevista. Quindi, nella maggior parte dei casi, quelli che si attengono alla generalizzazione falliscono rispetto a quelli che hanno abbracciato la composizione (tranne un caso ovvio menzionato in seguito). Quindi la regola. Da un punto di vista dell'apprendimento se è possibile implementare con successo un'iniezione di dipendenza, allora si dovrebbe sapere quale privilegiare e quando. La regola ti aiuta a prendere una decisione quando non sei sicuro di quale scegliere. Anche in questo caso dovresti essere in grado di vedere entrambe le opzioni in primo luogo per favorirne una.

Sommario: Composizione: l'accoppiamento viene ridotto semplicemente aggiungendo alcune cose più piccole che si inseriscono in qualcosa di più grande, e l'oggetto più grande richiama solo l'oggetto più piccolo indietro. Generazione: da un punto di vista dell'API di terze parti che definisce che un metodo può essere sovrascritto è un impegno più strong rispetto alla definizione di un metodo che può essere chiamato (sicuramente vincente per la generalizzazione). E non dimenticare mai che con la composizione usi anche la generalizzazione, da un'interfaccia invece che da una grande classe. Ma l'intero merito va alla composizione, purtroppo.

    
risposta data 26.10.2012 - 13:43
fonte
-4

Oggi ho scritto circa 300 LoC. E non riesco a ricordare alcun principio che potrei violare e non violato. Refactoring salverà la mia anima, spero.

Se l'astrazione è dettata da 3d party api - di solito è corretto usare l'ereditarietà. Nell'entità del design nazionale deve essere astratto o sigillato. L'entità astratta potenzialmente deve avere circa 3 ereditari. Non mi piacciono i punti di estensione metodo virtuale. Tutto sopra riguarda i miei gusti. Non sto parlando di astrazione dell'interfaccia, che è una storia diversa e completa.

    
risposta data 10.04.2011 - 18:43
fonte

Leggi altre domande sui tag