Certo, ma chiamiamo quella composizione e delega . Il modello di strategia e l'iniezione di dipendenza potrebbero sembrare strutturalmente simili ma i loro intenti sono diversi.
Il modello di strategia consente la modifica runtime del comportamento sotto la stessa interfaccia. Potrei dire a un'anatra selvatica di volare e guardarla volare con le ali. Quindi sostituiscilo con un'anatra pilota e guardalo volare con le compagnie aeree Delta. Farlo mentre il programma è in esecuzione è una cosa del modello di strategia.
L'iniezione di dipendenza è una tecnica per evitare dipendenze di codifica rigida in modo che possano cambiare in modo indipendente senza richiedere che i client vengano modificati quando cambiano. I clienti esprimono semplicemente i loro bisogni senza sapere come verranno soddisfatti. Pertanto, il modo in cui vengono incontrati viene deciso altrove (in genere nella parte principale). Non hai bisogno di due anatre per usare questa tecnica. Solo qualcosa che usa un'anatra senza sapere o preoccuparsi di quale anatra. Qualcosa che non costruisce l'anatra o non va a cercarla ma è perfettamente felice di usare qualunque anatra le passi.
Se ho una classe di anatre di cemento posso farla implementare il suo comportamento di volo. Potrei anche far cambiare i comportamenti da volare con le ali a volare con il Delta in base a una variabile di stato. Quella variabile potrebbe essere un valore booleano, un int o potrebbe essere FlyBehavior
un fly
metodo che ha uno stile di volo senza che io debba testarlo con un if. Ora posso cambiare gli stili di volo senza cambiare il tipo di anatra. Ora i germani reali possono diventare piloti. Questa è composizione e delega . L'anatra è composta da un FlyBehavior e può delegare ad esso richieste di volo. Puoi sostituire tutti i tuoi comportamenti da anatra in questo modo o tenere qualcosa per ogni comportamento o qualsiasi combinazione in mezzo.
Questo ti dà tutti gli stessi poteri che l'eredità ha tranne uno. L'ereditarietà ti consente di esprimere i metodi Duck che stai sostituendo nei sottotipi Duck. La composizione e la delega richiedono che l'Anatra deleghi esplicitamente ai sottotipi dall'inizio. Questo è molto più flessibile ma comporta una maggiore digitazione della tastiera e Duck deve sapere che sta accadendo.
Tuttavia, molte persone credono che l'eredità debba essere progettata esplicitamente fin dall'inizio. E che se non lo è stato, dovresti contrassegnare le tue classi come sigillate / definitive per impedire l'eredità. Se lo consideri, l'eredità non ha davvero alcun vantaggio rispetto alla composizione e alla delega. Perché in entrambi i casi devi progettare per l'estensibilità dall'inizio o essere disposto a demolire le cose in seguito.
Abbattere le cose è in realtà un'opzione popolare. Basta essere consapevoli del fatto che ci sono casi in cui è un problema. Se hai distribuito in modo indipendente librerie o moduli di codice che non intendi aggiornare con la prossima versione, puoi finire per occuparti di versioni di classi che non sanno nulla di ciò che stai facendo ora.
Mentre essere disposti a strappare le cose in un secondo momento può liberarti dalla progettazione eccessiva, c'è qualcosa di molto potente nel poter progettare qualcosa che usa un'anatra senza dover sapere cosa farà effettivamente l'anatra quando viene utilizzata. Quello non sapere è roba potente. Ti consente di smettere di pensare alle anatre per un po 'e pensare al resto del codice.
"Possiamo" e "dovremmo" sono domande diverse. Favorire la composizione sull'ereditarietà non dice mai di usare l'eredità. Ci sono ancora casi in cui l'eredità ha più senso. Ti mostrerò il mio esempio preferito :
public class LoginFailure : System.ApplicationException {}
L'ereditarietà consente di creare eccezioni con nomi più specifici e descrittivi in una sola riga.
Prova a farlo con la composizione e avrai un casino. Inoltre, non vi è alcun rischio del problema dell'ereditarietà perché non vi sono dati o metodi per riutilizzare e incoraggiare il concatenamento dell'ereditarietà. Tutto ciò aggiunge un buon nome. Non sottovalutare mai il valore di un buon nome.
Duckbehavior.quackBehavior
e altri campi "nel tuo codice?