Scala for Backend Engineering & Functional Programming · Leçon

Modélisation avec les ADT

Rendre les états illégaux impossibles à représenter

Leçon 1 sur 413 étapes

Modélisation avec les ADT est une leçon Scala for Backend Engineering & Functional Programming gratuite sur CoddyKit. Ceci est la leçon 1 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Scala for Backend Engineering & Functional Programming, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Scala for Backend Engineering & Functional Programming comprend 4 leçons au total.

Types de données algébriques

Les types de données algébriques (ADT) sont le fondement de la modélisation fonctionnelle des domaines. Ils combinent les types produit (AND) et les types somme (OR) pour décrire les données avec précision.

  • Produit : un enregistrement comportant plusieurs champs.
  • Somme : un choix entre plusieurs variantes.
case class Point(x: Int, y: Int) // product type

object Main:
  def main(args: Array[String]): Unit =
    println(Point(1, 2))

Types produit

Un type produit regroupe plusieurs valeurs. En Scala, une case class est un produit : une instance contient tous ses champs simultanément.

case class User(name: String, age: Int)

object Main:
  def main(args: Array[String]): Unit =
    val u = User("Ada", 36)
    println(u.name)
    println(u.age)

Types somme

Un type somme est une valeur qui correspond exactement à l’une de plusieurs variantes. Les énumérations de Scala 3 l’expriment directement.

enum PaymentMethod:
  case Cash
  case Card(number: String)
  case Crypto(wallet: String)

object Main:
  def main(args: Array[String]): Unit =
    val p: PaymentMethod = PaymentMethod.Card("1234")
    println(p)

Rendre les états illégaux impossibles à représenter

Le principe essentiel consiste à concevoir les types de sorte que les données invalides ne puissent même pas être construites. Si le système de types interdit un état incorrect, vous n’avez jamais besoin de le vérifier à l’exécution.

enum Connection:
  case Disconnected
  case Connected(sessionId: String)

object Main:
  def main(args: Array[String]): Unit =
    // No way to have a sessionId while Disconnected
    val c: Connection = Connection.Connected("abc")
    println(c)

Mauvaise conception ou bonne conception

Un enregistrement plat avec des champs pouvant être nuls favorise les états illégaux. Modéliser chaque cas comme une variante permet de les éliminer.

  • Mauvais : case class Conn(connected: Boolean, sessionId: String) autorise connected=false avec un sessionId.
  • Bon : un type somme associe le champ à l’état approprié.
enum Door:
  case Open
  case Closed
  case Locked(key: String)

object Main:
  def main(args: Array[String]): Unit =
    val d: Door = Door.Locked("k1")
    println(d)

Combiner produits et sommes

Les modèles réels imbriquent des produits dans des sommes, et inversement. Chaque variante peut contenir son propre produit de champs.

case class Address(city: String, zip: String)

enum Contact:
  case Email(value: String)
  case Postal(address: Address)

object Main:
  def main(args: Array[String]): Unit =
    val c: Contact = Contact.Postal(Address("Paris", "75001"))
    println(c)

Correspondance de motifs sur les ADT

Vous utilisez les ADT avec la correspondance de motifs. Comme le type est fermé, le compilateur vous avertit si vous oubliez une variante.

enum Shape:
  case Circle(r: Double)
  case Rect(w: Double, h: Double)

object Main:
  def area(s: Shape): Double = s match
    case Shape.Circle(r)  => 3.14159 * r * r
    case Shape.Rect(w, h) => w * h

  def main(args: Array[String]): Unit =
    println(area(Shape.Rect(2, 3)))

ADT récursifs

Les ADT peuvent se référer à eux-mêmes, ce qui permet de modéliser naturellement les arbres, les listes et les expressions.

enum Expr:
  case Num(value: Int)
  case Add(left: Expr, right: Expr)

object Main:
  def eval(e: Expr): Int = e match
    case Expr.Num(v)    => v
    case Expr.Add(l, r) => eval(l) + eval(r)

  def main(args: Array[String]): Unit =
    val e = Expr.Add(Expr.Num(2), Expr.Num(3))
    println(eval(e))

Gérer l’absence avec Option

Utilisez Option plutôt que null pour modéliser un champ potentiellement absent. Le type rend l’absence explicite et impose sa gestion.

case class Profile(name: String, nickname: Option[String])

object Main:
  def main(args: Array[String]): Unit =
    val p = Profile("Grace", None)
    println(p.nickname.getOrElse("(none)"))

Modéliser précisément les quantités

Évitez l’obsession des types primitifs. Au lieu d’utiliser des Int et des String bruts, encapsulez les quantités porteuses de sens afin que les types documentent l’intention et évitent les confusions.

case class Quantity(value: Int)
case class Price(cents: Long)
case class LineItem(qty: Quantity, price: Price)

object Main:
  def main(args: Array[String]): Unit =
    val item = LineItem(Quantity(3), Price(500))
    println(item)

Pourquoi les ADT sont importants

Les ADT vous apportent fiabilité et clarté.

  • Les états invalides ne peuvent pas être construits.
  • La correspondance exhaustive détecte les cas oubliés lors de la compilation.
  • La structure des données documente le domaine.
enum OrderStatus:
  case Pending
  case Shipped(tracking: String)
  case Delivered(at: Long)

object Main:
  def main(args: Array[String]): Unit =
    val s: OrderStatus = OrderStatus.Shipped("TRK1")
    println(s)

Vérification rapide

Vérifiez votre compréhension de la modélisation fondée sur les ADT.

Récapitulatif

Vous avez appris à modéliser un domaine avec des ADT.

  • Les types produit (case class) combinent des champs avec AND.
  • Les types somme (enum) proposent un choix avec OR.
  • Imbriquez-les pour modéliser des domaines riches et des structures récursives.
  • Utilisez Option plutôt que null.
  • Concevez vos types de sorte que les états illégaux ne puissent pas être représentés.
enum Event:
  case Created(id: Int)
  case Deleted(id: Int, reason: String)

object Main:
  def describe(e: Event): String = e match
    case Event.Created(id)         => s"created $id"
    case Event.Deleted(id, reason) => s"deleted $id: $reason"

  def main(args: Array[String]): Unit =
    println(describe(Event.Deleted(1, "spam")))
Gratuit pour commencer

Apprends Scala avec un tuteur IA — gratuit

Écris et exécute du vrai code dans ton navigateur, obtiens de l'aide instantanée d'un tuteur IA disponible 24h/24, et reprends là où tu t'es arrêté sur le web ou dans l'app.

Cours
39
Leçons
143

Questions Fréquemment Posées

La leçon « Modélisation avec les ADT » est-elle gratuite ?

Oui — le texte complet de « Modélisation avec les ADT » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Scala for Backend Engineering & Functional Programming, passe à CoddyKit PRO. Le cours Scala for Backend Engineering & Functional Programming comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Modélisation avec les ADT » ?

Rendre les états illégaux impossibles à représenter Tu pratiques Scala for Backend Engineering & Functional Programming avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer Scala for Backend Engineering & Functional Programming ?

Aucune expérience préalable n'est requise. Scala for Backend Engineering & Functional Programming sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 4.

Combien de temps prend la leçon « Modélisation avec les ADT » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon Scala for Backend Engineering & Functional Programming ?

Oui. Chaque leçon Scala for Backend Engineering & Functional Programming inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Modélisation avec les ADT
  2. Constructeurs intelligents
  3. Nouveaux types
  4. Composition des domaines
← Retour à Scala for Backend Engineering & Functional Programming