Ereditarietà e polimorfismo
Esplori i principi della programmazione orientata agli oggetti, come ereditarietà, classi astratte e polimorfismo in Scala.
Ereditarietà e polimorfismo è una lezione Scala for Backend Engineering & Functional Programming gratuita su CoddyKit. Questa è la lezione 2 di 2. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Scala for Backend Engineering & Functional Programming, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Scala for Backend Engineering & Functional Programming include 2 lezioni in totale.
Che cos'è l'ereditarietà?
L'ereditarietà è un concetto fondamentale della programmazione orientata agli oggetti (OOP) che consente a una nuova classe di ereditare proprietà e comportamenti (metodi) da una classe esistente.
La si può considerare come una relazione «padre-figlio». La classe «figlia» (sottoclasse) riutilizza il codice della classe «padre» (superclasse), risparmiando tempo e garantendo coerenza.
- Favorisce il riutilizzo del codice.
- Stabilisce una relazione «è-un» (ad esempio, un Dog è un Animal).
- Aiuta a organizzare il codice in una gerarchia.
La prima classe base
Definiamo una semplice classe Animal. Sarà la nostra classe base, chiamata anche superclasse o classe padre. Ha un comportamento di base: parlare.
Esegua il codice per vedere in azione il nostro animale generico!
class Animal {
val name: String = "Generic Animal"
def speak(): Unit = {
println(s"$name makes a sound.")
}
}
object Main {
def main(args: Array[String]): Unit = {
val myAnimal = new Animal()
myAnimal.speak()
}
}Estendere con `extends`
Ora creiamo un animale più specifico, un Dog. Un Dog è un Animal, quindi può ereditare dalla classe Animal usando la parola chiave extends.
Possiamo anche fare l'override del metodo speak per assegnare a Dog un verso particolare. Noti la parola chiave override.
class Animal {
val name: String = "Generic Animal"
def speak(): Unit = {
println(s"$name makes a sound.")
}
}
class Dog extends Animal {
override val name: String = "Dog"
override def speak(): Unit = {
println(s"$name barks!")
}
}
object Main {
def main(args: Array[String]): Unit = {
val myAnimal = new Animal()
val myDog = new Dog()
myAnimal.speak() // Generic Animal makes a sound.
myDog.speak() // Dog barks!
}
}La potenza di `override`
La parola chiave override è fondamentale in Scala per diversi motivi:
- Chiarezza: indica esplicitamente agli altri sviluppatori che questo metodo o campo sostituisce quello di una superclasse.
- Sicurezza: il compilatore verifica che si stia effettivamente facendo l'override di un membro esistente. In caso di errore di battitura o di modifica del metodo nella superclasse, il compilatore avvisa l'utente.
- Intento: indica chiaramente l'intenzione di specializzare o modificare il comportamento ereditato.
Usi sempre override quando ridefinisce membri ereditati!
Polimorfismo: molte forme
Il polimorfismo significa «molte forme». Nella programmazione orientata agli oggetti, consente di trattare oggetti di classi diverse come oggetti di una superclasse comune.
Ciò significa che si può avere una variabile di tipo Animal che contiene un oggetto Dog, un oggetto Cat o qualsiasi altra sottoclasse di Animal. Quando si chiama un metodo su quella variabile, viene eseguito il metodo corretto per il tipo effettivo dell'oggetto.
- Consente di creare codice flessibile ed estensibile.
- Permette di usare un'unica interfaccia per diversi tipi di dati.
- Si ottiene tramite l'override dei metodi.
Il polimorfismo nella pratica
Vediamo il polimorfismo in azione. Creeremo una classe Cat simile a Dog. Poi potremo inserire diversi tipi di animali in un elenco del loro supertipo comune, Animal, e chiamare il relativo metodo speak.
Noti come ogni animale produca il proprio verso, anche se nell'elenco vengono trattati tutti come tipi Animal.
class Animal {
val name: String = "Generic Animal"
def speak(): Unit = {
println(s"$name makes a sound.")
}
}
class Dog extends Animal {
override val name: String = "Dog"
override def speak(): Unit = {
println(s"$name barks!")
}
}
class Cat extends Animal {
override val name: String = "Cat"
override def speak(): Unit = {
println(s"$name meows!")
}
}
object Main {
def main(args: Array[String]): Unit = {
val animals: List[Animal] = List(
new Animal(),
new Dog(),
new Cat()
)
animals.foreach(_.speak())
}
}Presentazione delle classi astratte
A volte si desidera una classe base che definisca un'interfaccia comune, ma che non fornisca un'implementazione completa per alcuni dei suoi membri. È qui che entrano in gioco le classi astratte.
Una classe astratta:
- Non può essere istanziata direttamente (non è possibile creare un oggetto di una classe astratta).
- Può contenere metodi astratti (metodi senza implementazione) e metodi concreti (metodi con implementazione).
- Funge da modello che le sottoclassi devono completare.
Creare modelli astratti
Definiamo una abstract class Shape. Ogni forma ha un'area, ma la formula per calcolarla varia per ogni forma specifica (cerchio, rettangolo e così via).
Dichiariamo quindi area come metodo astratto. Noti che non ha un corpo (nessun = { ... }). Spetterà alle sottoclassi fornirne l'implementazione.
abstract class Shape {
def area: Double // Abstract method, no implementation
def describe(): Unit = {
println("This is a geometric shape.")
}
}
// You cannot do: new Shape() - it's abstract!
object Main {
def main(args: Array[String]): Unit = {
println("Abstract class Shape defined.")
println("Cannot instantiate Shape directly.")
}
}Implementazioni concrete
Ora creiamo sottoclassi concrete come Circle e Rectangle che estendono la nostra abstract class Shape. Queste sottoclassi devono fornire un'implementazione per il metodo astratto area.
Ereditano anche il metodo concreto describe() da Shape.
abstract class Shape {
def area: Double
def describe(): Unit = {
println("This is a geometric shape.")
}
}
class Circle(radius: Double) extends Shape {
override def area: Double = math.Pi * radius * radius
}
class Rectangle(width: Double, height: Double) extends Shape {
override def area: Double = width * height
}
object Main {
def main(args: Array[String]): Unit = {
val circle = new Circle(5)
val rectangle = new Rectangle(4, 6)
println(s"Circle area: ${circle.area}")
circle.describe()
println(s"Rectangle area: ${rectangle.area}")
rectangle.describe()
}
}Verifica su ereditarietà e polimorfismo
Quali delle seguenti affermazioni sull'ereditarietà e il polimorfismo in Scala sono VERE?
Riepilogo: ereditarietà e polimorfismo
Ottimo lavoro! In questa lezione abbiamo esplorato i concetti fondamentali della programmazione orientata agli oggetti in Scala:
- Ereditarietà: il modo in cui le sottoclassi riutilizzano il codice e definiscono una relazione «è-un» con le superclassi usando
extends. - Parola chiave
override: essenziale per ridefinire esplicitamente metodi e campi ereditati, garantendo sicurezza dei tipi e chiarezza. - Polimorfismo: la possibilità di trattare oggetti di sottoclassi diverse come oggetti di una superclasse comune, consentendo di creare codice flessibile ed estensibile.
- Classi astratte: modelli che non possono essere istanziati direttamente, usati per definire interfacce comuni e membri astratti che le sottoclassi devono implementare.
Questi concetti sono fondamentali per creare applicazioni Scala ben strutturate e facili da mantenere!
Domande Frequenti
La lezione «Ereditarietà e polimorfismo» è gratuita?
Sì — il testo completo di «Ereditarietà e polimorfismo» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Scala for Backend Engineering & Functional Programming, passa a CoddyKit PRO. Il corso Scala for Backend Engineering & Functional Programming include 2 lezioni in totale.
Cosa imparerò in «Ereditarietà e polimorfismo»?
Esplori i principi della programmazione orientata agli oggetti, come ereditarietà, classi astratte e polimorfismo in Scala. Eserciti Scala for Backend Engineering & Functional Programming con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Scala for Backend Engineering & Functional Programming?
Non è richiesta alcuna esperienza precedente. Scala for Backend Engineering & Functional Programming su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 2.
Quanto tempo richiede la lezione «Ereditarietà e polimorfismo»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Scala for Backend Engineering & Functional Programming?
Sì. Ogni lezione Scala for Backend Engineering & Functional Programming include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Classi, oggetti e pacchetti
- Ereditarietà e polimorfismo