Costruttori intelligenti
Costruzione con validazione
Costruttori intelligenti è una lezione Scala for Backend Engineering & Functional Programming gratuita su CoddyKit. Questa è la lezione 2 di 4. 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 4 lezioni in totale.
Costruzione validata
Un costruttore intelligente è una factory che valida gli input prima di produrre un valore. Garantisce che ogni istanza posseduta soddisfi le invarianti del tipo.
- Il costruttore grezzo è nascosto.
- Solo la creazione validata è pubblica.
class Age private (val value: Int)
object Age:
def of(v: Int): Option[Age] =
if v >= 0 then Some(new Age(v)) else None
object Main:
def main(args: Array[String]): Unit =
println(Age.of(30).map(_.value))Costruttore privato
Contrassegnare il costruttore principale come private impedisce ai chiamanti di aggirare la validazione. L'oggetto companion diventa l'unico punto di accesso.
class Percentage private (val value: Int)
object Percentage:
def of(v: Int): Option[Percentage] =
if v >= 0 && v <= 100 then Some(new Percentage(v)) else None
object Main:
def main(args: Array[String]): Unit =
println(Percentage.of(50).map(_.value))
println(Percentage.of(150))Restituire Option
Restituire Option segnala che la costruzione potrebbe fallire. Il chiamante deve gestire None, quindi i dati non validi non proseguono mai silenziosamente.
class NonEmpty private (val value: String)
object NonEmpty:
def of(s: String): Option[NonEmpty] =
if s.nonEmpty then Some(new NonEmpty(s)) else None
object Main:
def main(args: Array[String]): Unit =
println(NonEmpty.of("").map(_.value))
println(NonEmpty.of("hi").map(_.value))Restituire Either per i dettagli dell'errore
Quando desidera spiegare perché la validazione è fallita, restituisca Either[Error, T]. Il ramo Left contiene un messaggio descrittivo.
class Username private (val value: String)
object Username:
def of(s: String): Either[String, Username] =
if s.isEmpty then Left("empty")
else if s.length > 10 then Left("too long")
else Right(new Username(s))
object Main:
def main(args: Array[String]): Unit =
println(Username.of(""))
println(Username.of("ada").map(_.value))Costruttori intelligenti con case class
Anche una case class con costruttore privato funziona. Tenga presente che anche i metodi apply e copy generati devono essere controllati; definisca quindi una factory personalizzata e mantenga privato il costruttore.
case class Email private (value: String)
object Email:
def of(s: String): Option[Email] =
if s.contains("@") then Some(Email(s)) else None
object Main:
def main(args: Array[String]): Unit =
println(Email.of("a@b.com"))
println(Email.of("bad"))Comporre valori validati
Poiché i costruttori intelligenti restituiscono Option o Either, è possibile comporli con le comprehension for per costruire oggetti validati più grandi.
case class Name private (value: String)
object Name:
def of(s: String): Option[Name] =
if s.nonEmpty then Some(Name(s)) else None
case class Person(name: Name, age: Int)
object Main:
def make(n: String): Option[Person] =
for nm <- Name.of(n) yield Person(nm, 20)
def main(args: Array[String]): Unit =
println(Main.make("Bob"))Normalizzare l'input
Un costruttore intelligente può anche normalizzare i dati, ad esempio eliminando gli spazi superflui o convertendo in minuscolo, in modo che tutte le istanze condividano una forma canonica.
case class Tag private (value: String)
object Tag:
def of(s: String): Option[Tag] =
val clean = s.trim.toLowerCase
if clean.nonEmpty then Some(Tag(clean)) else None
object Main:
def main(args: Array[String]): Unit =
println(Tag.of(" Scala "))Le invarianti restano valide per sempre
Una volta superato il costruttore intelligente, il valore mantiene la propria invariante per tutta la sua durata. Il codice a valle può fidarsi del valore senza verificarlo nuovamente.
case class PositiveInt private (value: Int)
object PositiveInt:
def of(n: Int): Option[PositiveInt] =
if n > 0 then Some(PositiveInt(n)) else None
object Main:
def doubleIt(p: PositiveInt): Int = p.value * 2 // always positive
def main(args: Array[String]): Unit =
PositiveInt.of(5).foreach(p => println(Main.doubleIt(p)))Combinare con i tipi opachi
Per ottenere valori validati a costo nullo, abbini un costruttore intelligente a un tipo opaco. Non viene allocato alcun oggetto wrapper, ma la validazione continua a controllare la costruzione.
object Domain:
opaque type Score = Int
def of(n: Int): Option[Score] =
if n >= 0 && n <= 100 then Some(n) else None
extension (s: Score) def value: Int = s
object Main:
def main(args: Array[String]): Unit =
println(Domain.of(88).map(_.value))Più regole di validazione
Applichi diversi controlli in sequenza. La prima regola che fallisce interrompe la sequenza e restituisce un errore chiaro.
object Password:
def of(s: String): Either[String, String] =
if s.length < 8 then Left("too short")
else if !s.exists(_.isDigit) then Left("need a digit")
else Right(s)
object Main:
def main(args: Array[String]): Unit =
println(Password.of("abc"))
println(Password.of("abcdef12"))Quando usare i costruttori intelligenti
Li utilizzi ogni volta che un tipo presenta invarianti che la costruzione grezza potrebbe violare.
- Numeri entro un intervallo, stringhe non vuote, id formattati.
- Restituisca
Optionper un semplice sì/no,Eitherper indicare i motivi. - Mantenga privato il costruttore grezzo.
case class Port private (value: Int)
object Port:
def of(n: Int): Option[Port] =
if n >= 1 && n <= 65535 then Some(Port(n)) else None
object Main:
def main(args: Array[String]): Unit =
println(Port.of(8080))
println(Port.of(70000))Verifica rapida
Verifichi la sua comprensione dei costruttori intelligenti.
Riepilogo
Ha imparato a usare i costruttori intelligenti.
- Validi gli input in una factory companion.
- Renda privato il costruttore grezzo.
- Restituisca
OptionoEitherper imporre la gestione degli errori. - Normalizzi facoltativamente l'input in una forma canonica.
- Le invarianti saranno quindi valide per tutta la durata del valore.
case class Even private (value: Int)
object Even:
def of(n: Int): Option[Even] =
if n % 2 == 0 then Some(Even(n)) else None
object Main:
def main(args: Array[String]): Unit =
println(Even.of(4))
println(Even.of(5))Domande Frequenti
La lezione «Costruttori intelligenti» è gratuita?
Sì — il testo completo di «Costruttori intelligenti» è 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 4 lezioni in totale.
Cosa imparerò in «Costruttori intelligenti»?
Costruzione con validazione 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 4.
Quanto tempo richiede la lezione «Costruttori intelligenti»?
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
- Modellazione con gli ADT
- Costruttori intelligenti
- Newtype
- Composizione dei domini