Principio del Polimorfismo

Last Updated on 2 anni | Published: 27/04/2024

Polimorfismo Java

Il polimorfismo è uno dei concetti fondamentali della programmazione orientata agli oggetti (OOP), che offre flessibilità, estensibilità e chiarezza nel design del software. Questo principio consente a oggetti di classi diverse di essere trattati in modo uniforme, consentendo il riutilizzo del codice e una maggiore modularità. In questo articolo, esploreremo il polimorfismo, vedendo cosa significa, come funziona e come può essere utilizzato in Java per creare codice più robusto e manutenibile.

Il termine “polimorfismo” deriva dal greco antico e significa “molti forme”. In programmazione, si riferisce alla capacità di un oggetto di assumere molteplici forme. Ciò significa che un oggetto può essere trattato come un’istanza di una sua classe specifica, ma può anche essere trattato come un’istanza di una classe più generica dalla quale deriva.

In Java, il polimorfismo è supportato da classi astratte, interfacce e metodi sovrascritti. Le classi astratte possono avere metodi astratti che devono essere implementati nelle classi figlie. Inoltre, le classi figlie possono sovrascrivere i metodi della classe madre per fornire implementazioni specifiche.

Interfacce e Polimorfismo

Il prossimo esempio illustra l’ utilizzo delle interfacce e dell’ incapsulamento in un’applicazione che gestisce una lista di prodotti sfruttando appunto il principio del polimorfismo in Java:

package interfaccia

public interface IProdotti {

String getNome();

int getPrezzo();

}

public class Catalogo {
    private int size;
    private IProdotti[] prodotti;
 
    public Catalogo(int lunghezza) {
        prodotti = new IProdotti[lunghezza];
        size=0;
    }
    // Metodo per aggiungere un prodotto al catalogo
    public void addProdotto(IProdotti prodotto) {
        if (size < prodotti.length) {
            prodotti[size] = prodotto;
            size++;
        } else {
            System.out.println(“Catalogo pieno!“);
        }
    }    
    // Metodo per calcolare il costo totale del catalogo
    public double calcolaCostoTotale() {
        double costoTotale = 0;
        for (int i = 0; i < size; i++) {
            costoTotale += prodotti[i].getPrezzo();
        }
        return costoTotale;
    }
    public IProdotti[] dammiCatalogo() {
        return prodotti;  
    }
}
public class Dettagli implements IProdotti{
    private String nome;
    private int prezzo;
    public Dettagli(String nome, int prezzo) {
        this.nome=nome;
        this.prezzo=prezzo;
    }
    @Override
    public String toString() {
          return “Dettagli [nome=” + nome + “,
                      prezzo=” + prezzo + “]“;
    }
     @Override
     public String getNome() {
          return nome;
     }
    @Override
    public int getPrezzo() {
         return prezzo;
    }
}
public class Test {
    public static void main(String[] args) {
    // Creazione oggetto Catalogo con 3 prodotti
        Catalogo catalogo = new Catalogo(3);
        // Creazione di alcuni oggetti Dettagli
        IProdotti prodotto1 = new Dettagli(“Computer”, 1000);
         IProdotti prodotto2 = new Dettagli(“Mouse”, 20);
         IProdotti prodotto3 = new Dettagli(“Tastiera”, 80);
        // aggiunta prodotti al catalogo
        catalogo.addProdotto(prodotto1);
        catalogo.addProdotto(prodotto2);
        catalogo.addProdotto(prodotto3);
        System.out.println(catalogo.calcolaCostoTotale());

        IProdotti[] lista=catalogo.dammiCatalogo();

        for(IProdotti p:lista) {
               System.out.println(p);
        }
   }
}

Come menzionato in precedenza le interfacce non possono essere direttamente istanziate come oggetti, poiché sono solo contratti che definiscono un insieme di metodi che una classe deve implementare. Tuttavia, un array di tipo IProdotto[] può contenere riferimenti a oggetti che implementano l’interfaccia IProdotto e la logica dietro questa scelta è la seguente:

  1. Polimorfismo: Utilizzare un array di tipo IProdotti[] consente di sfruttare il polimorfismo in Java. Questo permette di trattare diversi tipi di prodotti in modo uniforme, poiché l’array può contenere riferimenti a oggetti di qualsiasi classe che implementa l’interfaccia IProdotti che nel nostro esempio è la classe Dettagli
  2. Separazione delle Responsabilità: Mantenendo l’array di tipo IProdotti[], si separa la definizione dell’interfaccia IProdotti dalla sua implementazione. Questo rende il codice più modulare, flessibile e manutenibile.
  3. Estensibilità: Se in futuro si desidera aggiungere nuovi tipi di prodotti, sarà sufficiente creare nuove classi che implementano l’interfaccia IProdotti e aggiungerle all’array esistente, senza dover modificare il codice che gestisce l’array.
  4. Incapsulamento: L’array di tipo Prodotto[] è dichiarato come privato nella classe in cui è utilizzato, e viene utilizzato per incapsulare la logica interna della gestione dei prodotti. Questo protegge l’integrità dei dati e fornisce un’interfaccia controllata per accedere ai prodotti.

Classi Astratte e Polimorfismo

Vediamo un semplice esempio dell’ implementazione di una classe astratta Figura, con un metodo astratto calcolaArea() ed un metodo concreto stampaTipo()

// Classe astratta Figura
public abstract class Figura {

    // Metodo astratto calcolaArea
    public abstract  double  calcolaArea();

    // Metodo concreto stampaTipo
    public void stampaTipo() {
        System.out.println(“Sono una figura generica.“);
    }
}

// Classe Cerchio che estende Figura
public class Cerchio extends Figura {

    private double raggio;

    public Cerchio(double raggio) {
        this.raggio = raggio;
    }

    @Override
    public double calcolaArea() {
        return Math.PI * raggio * raggio;
    }

}

public class Test {

    public static void main(String[] args){
         Figura figura = new Cerchio(5.0);
         System.out.println(“Area del cerchio: ” +

                                            figura.calcolaArea());
        // Stampa: “Area del cerchio: 78.53981633974483″
        figura.stampaTipo();
      // Stampa: “Sono una figura generica.”
    }
}

In questo esempio, la classe Figura è una classe astratta con un metodo astratto calcolaArea() e un metodo concreto stampaTipo(). La classe Cerchio estende Figura, implementando il metodo astratto calcolaArea(). Utilizzando un riferimento di tipo Figura, possiamo riferire un oggetto Cerchio, sfruttando il polimorfismo offerto dalle classi astratte, ed un oggetto Rettangolo con i suoi attributi per calcolare l’ area.

Polimorfismo tra Classi Concrete

Di seguito un esempio di Polimorfismo tra classi concrete e metodi sovrascritti per la gestioni di Veicoli:

Classe Veicoli
Classe Auto
Classe Moto
Classe di Test

Le classi parametriche, spesso definite come generiche, costituiscono uno strumento potente nel linguaggio di programmazione Java. Consentono la creazione di classi e metodi che possono essere usati con diversi tipi di dati …….

LABORATORIO

Esempio di polimorfismo attraverso l’ interfaccia IProdotti che definisce due metodi getNome() e getPrezzo(). Questa interfaccia rappresenta il contratto che deve essere rispettato in tutte le classi che rappresentano prodotti.

Esempio in cui la classe astratta Prodotti ha attributi comuni a tutti prodotti come nome, prezzo e disponibilità e definisce un metodo astratto calcolaSconto(), che rappresenta un’ operazione comune. La classe Libri estende Prodotti e fornisce una implementazione concreta.

In questo esempio abbiamo una classe astratta Persone che rappresenta una entità generica che ha attributi comuni a tutte le persone. Studenti estende Persone ereditando quindi gli attributi ed i metodi comuni a tutte le persone.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *