Constructores inteligentes
Construcción validada
Constructores inteligentes es una lección gratuita de Scala for Backend Engineering & Functional Programming en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Scala for Backend Engineering & Functional Programming, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Scala for Backend Engineering & Functional Programming incluye 4 lecciones en total.
Construcción validada
Un constructor inteligente es una fábrica que valida las entradas antes de producir un valor. Garantiza que cualquier instancia que conserve cumpla las invariantes del tipo.
- El constructor original está oculto.
- Solo se expone la creación validada.
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))Constructor privado
Marcar el constructor principal como private impide que los clientes omitan la validación. El objeto acompañante se convierte en el único punto de entrada.
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))Devolver Option
Devolver Option indica que la construcción puede fallar. El cliente debe gestionar None, por lo que los datos no válidos nunca siguen circulando silenciosamente.
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))Devolver Either para detallar el error
Cuando quiera explicar por qué falló la validación, devuelva Either[Error, T]. El valor Left contiene un mensaje descriptivo.
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))Constructores inteligentes con case class
Una case class con un constructor privado sigue funcionando. Tenga en cuenta que sus apply y copy generados también deben controlarse, por lo que debe definir una fábrica personalizada y mantener privado el constructor.
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"))Encadenar valores validados
Como los constructores inteligentes devuelven Option o Either, puede combinarlos mediante expresiones for para construir objetos validados más grandes.
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"))Normalizar la entrada
Un constructor inteligente también puede normalizar los datos, por ejemplo, eliminando espacios en blanco o convirtiendo el texto a minúsculas, para que todas las instancias compartan una forma canónica.
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 "))Las invariantes se mantienen siempre
Una vez que un valor supera el constructor inteligente, su invariante queda garantizada durante toda su vida útil. El código posterior puede confiar en el valor sin volver a comprobarlo.
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)))Combinar con tipos opacos
Para obtener valores validados sin coste adicional, combine un constructor inteligente con un tipo opaco. No se asigna ningún objeto envoltorio, pero la validación sigue controlando la construcción.
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))Varias reglas de validación
Aplique varias comprobaciones en secuencia. La primera regla que falla interrumpe el proceso y devuelve un error claro.
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"))Cuándo usar constructores inteligentes
Úselos siempre que un tipo tenga invariantes que la construcción directa pueda incumplir.
- Números acotados, cadenas no vacías e identificadores con formato.
- Devuelva
Optionpara un resultado simple de sí o no yEitherpara explicar los motivos. - Mantenga privado el constructor original.
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))Comprobación rápida
Compruebe su comprensión de los constructores inteligentes.
Resumen
Ha aprendido los constructores inteligentes.
- Valide las entradas en una fábrica del objeto acompañante.
- Haga privado el constructor original.
- Devuelva
OptionoEitherpara obligar a gestionar los fallos. - Normalice opcionalmente la entrada a una forma canónica.
- De este modo, las invariantes se mantienen durante toda la vida útil del valor.
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))Preguntas frecuentes
¿La lección «Constructores inteligentes» es gratis?
Sí — el texto completo de «Constructores inteligentes» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Scala for Backend Engineering & Functional Programming, actualiza a CoddyKit PRO. El curso de Scala for Backend Engineering & Functional Programming incluye 4 lecciones en total.
¿Qué aprenderé en «Constructores inteligentes»?
Construcción validada Practicas Scala for Backend Engineering & Functional Programming con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Scala for Backend Engineering & Functional Programming?
No se requiere experiencia previa. Scala for Backend Engineering & Functional Programming en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.
¿Cuánto tiempo toma la lección «Constructores inteligentes»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Scala for Backend Engineering & Functional Programming?
Sí. Cada lección de Scala for Backend Engineering & Functional Programming incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Modelado con ADT
- Constructores inteligentes
- Newtypes
- Composición de dominios