La programmazione ad oggetti si basa fondamentalmente su tre principi:
- incapsulamento: è la capacità di nascondere all'esterno dati e servizi, inglobandoli in un modulo che risulti inviolabile dall'esterno.
- ereditarietà: è la capacità di estendere un modulo aggiungendo o modificando alcuni dei suoi servizi.
- polimorfismo: è la capacità di variare il comportamento di un modulo a seconda di come viene acceduto.
- può nascondere i dettagli implementativi dei propri dati all'esterno (incapsulamento).
- può essere estesa da una classe figlia, che implementi ulteriori servizi (ereditarietà).
- può venire acceduta con ciascuna interfaccia appartenente ad una delle sue superclassi, ma il suo comportamento dipenderà dalla sua implementazione concreta (polimorfismo).
Per meglio chiarire, si consideri il seguente esempio:
public class Automobile{
// incapsulamento: la velocità e' nascosta all'esterno e può essere
// acceduta solo tramite opportuni servizi
protected int speed = 0;
// servizio pubblico per variare la velocita', si noti che il chiamante
// non conosce nessun dettaglio implementativo circa la velocita'
public void accelera(){ this.speed++; }
}
public class AutomobileSportiva extends Automobile {
// l'automobile sportiva utilizza come base Automobile
// Un'auto sportiva ha una accelerazione forte. Si noti che si ridefinisce
// un servizio che si basa sulle proprieta' del codice vecchio, ossia la variabile
// speed.
public void accelera(){
for(int i=0; i<4;>
this.accelera();
}
}
Si supponga che in un programma ci sia un metodo che utilizza l'automobile:
public void corri(Automobile auto){ auto.accelera(); }
Ora, è evidente che se a questo metodo viene passata un'istanza di AutomobileSportiva, il codice in questione (vecchio) utilizza il nuovo comportamento (polimorfismo). Ecco quindi che senza alterare il codice vecchio si è inserito un comportamento nuovo, e quindi il codice vecchio usa il codice nuovo. Similarmente, AutomobileSportiva rappresenta codice nuovo che utilizza quello vecchio: il suo metodo accelera() richiama il codice vecchio della superclasse.
Da notare come il comportamento ottenuto dipenda dal tipo run-time effettivo, ossia il polimorfismo mostra sempre l'ultimo comportamento definito nel tipo run-time fra quelli disponibili a partire dal tipo statico.
Si noti che il polimorfismo da solo non basta: è indispensabile disporre anche del principio di sostituzione di Liskov, che consente di utilizzare l'interfaccia di una superclasse per riferirsi ad una sottoclasse.
Nessun commento:
Posta un commento