Principio di sostituzione, regola dei metodi e delle proprietà. Perchè Java usa la parola chiave "extends"?

Prendo spunto dal post di Emanuele, "OOP != Ereditarietà". Volevo però fare delle considerazioni. Innanzitutto:

  • Una sottoclasse non è un sottotipo. I sottotipi devono rispettare il principio di sostituzione, per le sottoclassi questa proprietà non è richiesta.
  • In un linguaggio orientato agli oggetti, i sottotipi sono implementati con sottoclassi.
  • Se si usa un approccio disciplinato all'ereditarietà, ogni sottoclasse è un sottotipo.

Nei linguaggi fortemente tipizzati, la correttezza di una sottoclasse è verificata dal compilatore. Una sottoclasse ha tutti metodi della superclasse e le signature dei metodi sono compatibili (regola della signatura).

Per un sottotipo devono valere anche la regola dei metodi e la regola delle proprietà. Tali regole, insieme alla regola della signatura, garantiscono che sia rispettato il principio di sostituzione. I compilatori in genere non sono in grado di verificare nulla a questo riguardo. Per valutare se queste regole siano rispettate è necessario avere a disposizione una specifica del tipo di dato astratto (contratto dei metodi e invariante astratto di rappresentazione). Linguaggi di specifica formale e relativi tools, in genere, possono essere d'aiuto. Vediamo in cosa consistono queste due regole.

Il contratto di un metodo è definito da ciò che il metodo si aspetta dal chiamante (talvolta definite clausole requires) e dalle promesse che il metodo fà al chiamante (talvolta definite clausole ensures). Secondo la  regola dei metodi, i metodi ridefiniti da un sottotipo devono estendere il contratto per essi definito nel supertipo. In questo senso, le clausole requires nel sottotipo devono essere meno restrittive di quelle nel supertipo. Le clausole ensures possono offrire qualcosa in più di quanto garantito dal supertipo, ma mai qualcosa in meno. Ricordo che una volta Andrea si disse contrario alla scelta della parola chiave extends da parte dei progettisti di Java. Il modo in cui va interpretata e proprio questo: un sottotipo estende il comportamento del supertipo, non può semplicemente ridefinirlo con qualcosa di diverso. Scrivendo un sottotipo, si può ridefinire un metodo, ma il suo contratto può solo essere esteso, non ridefinito. OK, nulla vieta di farlo, ma è scorretto se si sta seguendo un approccio disciplinato all'ereditarietà.

L'invariante astratto di rappresentazione di un tipo, è l'insieme delle proprietà che valgono sempre per un oggetto di quel tipo. Secondo la regola delle proprietà, i metodi ridefiniti da un sottotipo non devono violare l'invariante di rappresentazione del supertipo.


Alla luce di tutto questo, vediamo l'esempio di Emanuele su ArrayList. Microsoft, purtroppo, non ci dà una specifica formale del framework. Secondo MSDN, il metodo ArrayList#Sort():

"Sorts the elements in the entire ArrayList using the IComparable implementation of each element."

A seconda di come si interpreta la frase, MyArrayList può rispettare o non rispettare il principio di sostituzione. È un problema di lingua inglese. Dal mio punto di vista, dire che il metodo ordina ("sort") gli elementi non significa necessariamente in ordine crescente.

Se per voi, come per me, "sort" significa semplicemente ordinare, allora MyArrayList è un sottotipo e rispetta il principio di sostituzione. Infatti, il chiamante del metodo non deve aspettarsi che l'array sia ordinato in ordine crescente. Il fatto che ArrayList lo faccia, non significa che anche i suoi sottotipi, qualora ridefiniscano il metodo, debbano farlo. L'importante è che la lista venga ordinata secondo l'implementazione di IComparable da parte degli elementi.

Se per voi "sort" significa, di default, ordinare in ordine crescente, allora MyArrayList è una sottoclasse ma non un sottotipo, poichè viola il principio di sostituzione. In questo caso, l'esempio di Emanuele è pertinente.


Magari quando ho tempo aggiorno il post con qualche esempio... Detto così sembra molto teorico. Lo è, ma con notevoli riscontri nella pratica!

Print | posted on giovedì 3 agosto 2006 19:17