Ereditarietà in Java: ricerca

Tra gli elementi più importanti che caratterizzano il paradigma di sviluppo OOP c’è la Gerarchia. Tenendo a mente questo fatto non è difficile convincersi di quanto il concetto di ereditarietà sia centrale nella programmazione Object Oriented.

In informatica l’ereditarietà è uno dei concetti fondamentali nel paradigma di programmazione a oggetti. Essa consiste in una relazione che il linguaggio di programmazione, o il programmatore stesso, stabilisce tra due classi. Se la classe B eredita dalla classe A, si dice che B è una sottoclasse di A e che A è una superclasse di B. Denominazioni alternative equivalenti, sono classe madre o classe base per A e classe figlia o classe derivata per B. A seconda del linguaggio di programmazione, l’ereditarietà può essere ereditarietà singola o semplice (ogni classe può avere al più una superclasse diretta) o multipla (ogni classe può avere più superclassi dirette).

In generale, l’uso dell’ereditarietà dà luogo a una gerarchia di classi; nei linguaggi con ereditarietà singola, si ha un albero se esiste una superclasse “radice” unica di cui tutte le altre sono direttamente o indirettamente sottoclassi (come la classe Object nel caso di Java) o a una foresta altrimenti; l’ereditarietà multipla definisce invece una gerarchia a grafo aciclico diretto.

DEFINIZIONE

Riassumendo: si dice che una classe A è una sottoclasse di B (e analogamente che B è una superclasse di A) quando:

  • Aeredita da B sia il suo stato che il suo behavior (comportamento)
  • e quindi un’istanza della classe Aè utilizzabile in ogni parte del codice in cui sia possibile utilizzare una istanza della classe B.

Questa ultima parte della definizione va sotto il nome di “Principio di sostituzione di Liskov” ed è un invariante di importanza capitale che va tenuto presente ogni volta che si pensa a come strutturare una gerarchia di classi.

 

PER I PROGRAMMATORI:

Durante lo sviluppo di codice frequentemente i programmatori sviluppano codice molto simile a codice gia esistente . Questo, spesso, viene fatto manipolando il codice esistente con operazioni di “cut” e “paste”

Non è utile né opportuno modificare codice già funzionante e corretto il cui sviluppo ha richiesto tempo (anni-uomo) ed è costato (molto) denaro, occorre quindi un modo per catturare le similitudini e formalizzarle, ed un linguaggio che consenta di progettare codice in modo incrementale.

 

VANTAGGI

L’ereditarieta’ consente di riutilizzare in modo vantaggioso una classe gia’ definita che e’ simile a quella che vogliamo definire e consente di utilizzare il polimorfismo.

Attraverso l’estensione della classe pre-esistente (chiamata “superclasse”), noi possiamo:

  • aggiungere nuovi dati (attributi) a quelli presenti nella superclasse
  • aggiungere nuovi metodi a quelli presenti nella superclasse, eventualmente con overloading (caratteristica ortogonale all’ereditarietà)
  • ridefinire alcuni metodi della superclasse secondo le nuove esigenze (Overriding dei metodi)

Uno dei principali vantaggi dell’uso dell’ereditarietà (in particolare combinata col polimorfismo) è il fatto di favorire il riuso di codice. Non solo una sottoclasse eredita (e quindi riusa) il codice della superclasse: il polimorfismo garantisce anche che tutto il codice precedentemente scritto per manipolare oggetti della superclasse sia anche implicitamente in grado di manipolare oggetti della sottoclasse. Per esempio, un programma che sia in grado di rappresentare graficamente oggetti di classe Quadrilatero non avrebbe bisogno di alcuna modifica per trattare analogamente anche oggetti di una eventuale classe Rettangolo.

 

CLASSI

La nuova classe:

  • si dice che (CLASSE DERIVATA o SOTTOCLASSE) erediti dalla pre-esistente classe A (CLASSE BASE o SUPERCLASSE)
  • La nuova classe che ESTENDE un classe già esistente
  • può aggiungere nuovi dati o metodi
  • può accedere ai dati ereditati purché il livello di protezione lo consenta
  • non può eliminare dati o metodi perché il principio di base dei linguaggi OO è che dovunque si usa un oggetto della classe madre deve essere possibile sostituirlo con un oggetto di una qualunque delle classi figlie

La classe derivata condivide quindi la struttura e il comportamento della classe base

 

COSA SI EREDITA?

Tutti i dati della classe base anche quelli privati, a cui comunque la classe derivata non potrà accedere direttamente tutti i metodi anche quelli che la classe derivata non potrà usare direttamente tranne i costruttori, perché sono specifici di quella particolare classe.

 

ESEMPI

Supponiamo che in un programma si usi una classe “Animale” contenente dati per specificare, ad esempio, se l’animale è vivo, il luogo in cui si trova, quante zampe ha, ecc.; in aggiunta a questi dati la classe potrebbe contenere anche metodi per descrivere come l’animale mangia, beve, si muove, si accoppia, ecc. Se si volesse creare una classe “Mammifero” molte di queste caratteristiche rimarrebbero esattamente le stesse di quelle dei generici animali, ma alcune sarebbero diverse. Diremmo quindi che “Mammifero” è una sottoclasse della classe “Animale” (oppure, inversamente, che “Animale” è la classe classe base – chiamata anche classe genitrice – di “Mammifero”). La cosa importante da notare è che nel definire la nuova classe non è necessario specificare nuovamente che un mammifero ha le normali caratteristiche di un animale (luogo in cui si trova, il fatto che mangia, beve, ecc), ma basta aggiungere le caratteristiche peculiari che contraddistinguono i mammiferi rispetto agli altri animali (ad esempio, che è ricoperto di pelo e ha le mammelle, e ridefinire le funzioni che, pur essendo comuni a tutti gli altri animali, si manifestano in modo diverso, ad esempio il modo di riprodursi. Nell’esempio che segue, scritto in Java, notare all’interno del metodo riproduciti() la chiamata a super.riproduciti(), che è un metodo della classe base che si sta ridefinendo. Per usare parole semplici si potrebbe dire che questo metodo dice di “fare prima tutto quello che la classe base farebbe” seguito poi dal codice che indica quali sono le “cose in più” che deve fare la nuova classe.

class Mammifero extends Animale {
    Pelo pelo;
    Mammelle mammelle;

    Mammifero riproduciti() {
        Mammifero prole;

        super.riproduciti();
        if(isFemmina()) {
            prole = super.partorisci();
            prole.allatta(m_b);
        }
        curaCuccioli(prole);
        return prole;
    }
}

 

 

Sitografia:

Precedente OOP: manipolatore stringhe Successivo OOP: password