La composizione è quando una classe offre alcune funzionalità creando un'istanza di una classe (possibilmente interna) che implementa già questa funzionalità, invece di ereditare da quella classe.
Quindi, ad esempio, se hai una classe che modella una nave, e ti viene ora detto che la tua nave dovrebbe offrire un posto di atterraggio, non è naturale per la tua nave derivare da un eliporto, (duh!), invece, dovresti fare in modo che la tua nave contenga una classe di eliporto e esponila tramite un metodo Ship.getHelipad()
.
In anni (un decennio fa) le persone erano solite considerare l'ereditarietà come un modo semplice e veloce di aggregare le funzionalità, quindi c'erano molti esempi del tipo di "nave che eredita dall'eliporto", che erano, ovviamente, molto zoppo.
Ma il motto "Favorisci la successione all'ereditarietà" è stato accuratamente formulato per chiarire che questo è solo un suggerimento, non una regola. L'autore del motto è stato abbastanza prudente da astenersi dal dire qualcosa come "tu mai usare l'ereditarietà, solo composizione". Questo in sostanza sta portando all'attenzione della comunità dell'ingegneria del software il fatto che l'ereditarietà sia stata abusata, mentre in molti casi la composizione produce disegni più chiari, eleganti e mantenibili rispetto all'ereditarietà.
Quindi, in sostanza, il detto "Favorisci l'ereditarietà" suggerisce che ogni volta che ti trovi di fronte al "ereditare o comporre?" domanda, dovresti riflettere seriamente quale sia la strategia più adatta e che la maggior parte delle probabilità è che la strategia più adatta si rivelerà essere la composizione, non l'ereditarietà.
Ma poiché questa non è una regola, dovresti anche tenere presente che ci sono molti casi in cui l'ereditarietà è più naturale. Se usi la composizione là dove avresti dovuto usare l'ereditarietà, molti mali cadranno nel tuo codice.
Per tornare all'esempio di nave, se la tua nave ha bisogno di offrire un'interfaccia per interagire con un FloatingMachine
, allora è più naturale derivarla da una classe astratta FloatingMachine
, che molto probabilmente potrebbe a sua volta essere derivato da un'altra classe astratta Machine
.
Ecco la regola generale per la risposta alla domanda di composizione vs. ereditarietà:
Does my class have an "is a" relationship to the interface that it
needs to expose? If yes, use inheritance. If not, use composition.
Una nave "è una" macchina mobile e una macchina mobile "è una" macchina ". Quindi l'ereditarietà è perfetta per quelli. Ma una nave non è, ovviamente, un eliporto. Quindi è meglio comporre la funzionalità dell'eliporto.