Cos’è il polimorfismo? E perché vale la pena imparare

Se puoi guidare un'auto per pendolari a 4 porte, puoi anche guidare un camioncino. Se hai guidato un'auto con un motore a combustione, puoi anche guidare un'auto elettrica.

La forma e le dimensioni delle autovetture possono essere diverse da una all'altra. Anche il motore che fa funzionare quei veicoli potrebbe essere completamente diverso. Ma non importa all'autista.

Devi solo entrare, allacciare le cinture, avviare il veicolo, metterlo in marcia e guidare. Questo perché auto, camion e furgoni sono polimorfici .

Polimorfismo: scomporlo

Diamo un'occhiata alla parola polimorfismo. Puoi scomporlo in poli , metamorfosi e ismo .

Poly significa molti, come il modo in cui poligono significa molti angoli. Quando viene usato come nome, un morph è una variante di una specie. E ismo può significare sistema.

Quindi polimorfismo significa semplicemente un sistema di molte variazioni. Tuttavia, questo non ti dice ancora molto su come viene utilizzato nella programmazione. Quello è il prossimo.

Se cammina come un'anatra … Perché gli oggetti polimorfici sono fantastici

Quando crei una classe nel tuo codice che eredita da un'altra classe, stai vincolando la nuova classe a un contratto. Il contratto afferma che ogni variabile e funzione nel genitore sarà anche nel figlio.

Ogni veicolo ha un volante, pedali dell'acceleratore e del freno e un indicatore di direzione. Non è necessario aprire il cofano per guidare una macchina. Tutto ciò che conta è che sia un'auto.

La stessa cosa si applica alle classi che ereditano da altre classi. Ecco un esempio in TypeScript:

 
class Vehicle {
private _engine: string;
private _tires: number;
constructor(engine: string = "combustion", tires: number = 4) {
this._engine = engine;
this._tires = tires;
}
accelerate(velocity: number) {
console.log("accelerating at a velocity of " + velocity);
}
brake(pressure: number) {
console.log("applying " + pressure + " pressure");
}
turnLeft() {
console.log("turning left");
}
turnRight() {
console.log("turning right");
}
}
class Car extends Vehicle {
}
class Tesla extends Car {
constructor() {
super("electric");
}
}

In questo esempio, c'è una classe Vehicle . La classe Car eredita dalla classe Vehicle . E Tesla eredita da Car . Ora creiamo un paio di oggetti e guardiamoli.

 let myCoupe: Car = new Vehicle();
console.log(myCoupe);
console.log(myCoupe.constructor.name);
let mySedan: Vehicle = new Tesla();
console.log(mySedan);
console.log(mySedan.constructor.name);
myCoupe.turnLeft();
mySedan.turnLeft();

Come puoi vedere, abbiamo dichiarato myCoupe un'auto e mySedan un veicolo . Quindi abbiamo istanziato myCoupe come nuovo veicolo e mySedan come nuova Tesla . Se visiti la sandbox TypeScript ed esegui il codice, vedrai che funziona senza errori . E si comporta come ti aspetteresti, in base al contratto.

In altre parole, tutti i veicoli possono svoltare a sinistra perché l'hanno ereditata dalla classe Veicolo . Il compilatore sa che ogni figlio di Vehicle ha accettato il contratto. Quindi presume che tutto vada bene, indipendentemente dalle classi in cui gli oggetti sono stati digitati o istanziati.

Questo a volte è chiamato "dattilografia". Il compilatore presume che se cammina come un'anatra e parla come un'anatra, potrebbe anche essere un'anatra. Quindi il compilatore non si preoccupa dei dettagli e tratta l'oggetto come una papera.

Il polimorfismo rende il tuo codice a prova di proiettile

Un altro vantaggio del contratto del polimorfismo è la garanzia che il codice funzionerà. Se hai digitato fortemente tutte le tue variabili e ciò che ogni funzione restituisce, sai che ogni bambino corrisponderà sempre a variabili, funzioni e tipi.

Ciò significa che puoi aggiungere e modificare il codice nelle tue classi senza interrompere il programma. Ogni oggetto che fa riferimento a un oggetto Veicolo riceverà sempre dati e funzionalità che soddisfano le aspettative, indipendentemente da quanto l' auto cambia.

Il codice all'interno della funzione potrebbe non fornire i risultati corretti. Ma questo è un tipo diverso di problema. Finché la funzione segue il contratto e restituisce il tipo di variabile previsto, non si verificherà un errore di rottura del codice.

Il polimorfismo è enorme e qui ci sono altri 10 principi di programmazione che dovresti conoscere .

Pratica il polimorfismo

  • Usa il link sandbox sopra per creare una classe Boat .
  • Crea un'istanza di un nuovo oggetto barca in modo tale che sia un tipo Veicolo , ma sembri comunque una barca.
  • Assicurati che la barca si comporti ancora come un veicolo.

Un ultimo esempio di polimorfismo

Il polimorfismo può essere un concetto difficile da comprendere inizialmente. Ma una volta ottenuto, hai fatto un enorme passo avanti verso la comprensione di cosa sia veramente la programmazione orientata agli oggetti. Tuttavia, il concetto può ancora sembrare teorico. Quindi ecco un solido esempio del mondo reale per aiutarti a vedere quanto sia utile.

Immagina di creare un'app Web che si connette a un database MySQL. Quindi il capo decide di passare a un database PostgreSQL. Significa che devi riscrivere tutte le chiamate al database?

No, non è così. Se la tua app utilizza una classe DataAccess con sottoclassi che in realtà si confondono con i dati, sei fortunato. La classe DataAccess definisce il modo in cui la tua app interagisce con i dati, non come interagisce con il database.

Hai sottoclassi come MySQLAccess e PostgresQLAccess che fanno tutto il lavoro sporco. Ma se la tua app ha solo oggetti DataAccess , puoi scambiare i database senza riscrivere una singola riga di codice dell'app.