Per fornire un contesto, ho visto recentemente alcuni commenti che equivalgono ad ereditare il comportamento da un supertipo, ereditando un'interfaccia pura senza alcun comportamento. Ma ci sono conseguenze piuttosto significative e diverse per ciascuno.
es. Ecco una classe base di esempio e un'interfaccia "pura" (pseudocodice):
class FlyingBird {
void fly() {
change state due to flight
}
}
interface Flyable {
void fly();
}
Ora diciamo che ho Swan and Dove. Sarò sottoclasse Swan da FlyingBird, e farò implementare la colomba Flyable.
Swan extends FlyingBird {
(no defnition for fly, because we inherit it from FlyingBird)
}
Dove implements Flyable {
void fly() {
... must provide implementation for fly, because the interface only provides the signature
}
Ora posso chiamare sia swan.fly () che dove.fly (), ma swan ottiene la sua implementazione da FlyingBird. L'espressione "Favorisci la composizione sull'ereditarietà" mi dice di favorire l'implementazione di Colomba su Swan, con una sorta di implementazione iniettata, ma "il polimorfismo del sottotipo" non sembra fare questa distinzione.
La distinzione è importante, perché, ad esempio:
-
C'è un crescente movimento in OO per rendere le classi "definitive" o "non-estendibili" di default, a causa della complessità del comportamento ereditario senza rompere la semantica delle super-classi. In altre parole, alcune persone suggeriscono che una forma di prototipo di sottotipo debba essere disabilitata di default. (Non ho sentito nessuno suggerire di eliminare le interfacce in Java.)
-
"Favorisci la composizione sull'ereditarietà" differenzia il comportamento di condivisione attraverso l'ereditarietà della classe e fornisce un'interfaccia comune supportata da un'implementazione condivisa.
In altre parole, ci sono differenze pratiche e importanti tra il comportamento ereditario e l'ereditare un'interfaccia.
Il polimorfismo del sottotipo distingue tra comportamento ereditario o ereditare un'interfaccia?