Scala for Backend Engineering & Functional Programming · Aula

Composição de domínios

Construa modelos maiores

Aula 4 de 413 etapas

Composição de domínios é uma aula grátis de Scala for Backend Engineering & Functional Programming no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Scala for Backend Engineering & Functional Programming, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Scala for Backend Engineering & Functional Programming inclui 4 aulas no total.

Construindo modelos maiores

Domínios reais são montados a partir de componentes menores. Compor domínios significa combinar ADT, newtypes e valores validados bem modelados em estruturas maiores que continuam corretas.

  • Tipos pequenos e focados podem ser combinados em tipos maiores.
  • Cada componente mantém suas próprias invariantes.
case class Money(cents: Long)
case class Product(name: String, price: Money)

object Main:
  def main(args: Array[String]): Unit =
    println(Product("Book", Money(1999)))

Aninhando produtos

Componha tipos produto aninhando case classes. Cada nível adiciona estrutura sem perder a legibilidade.

case class Address(city: String, zip: String)
case class Customer(name: String, address: Address)

object Main:
  def main(args: Array[String]): Unit =
    val c = Customer("Ada", Address("London", "E1"))
    println(c.address.city)

Compondo com coleções

Use List, Map e Set para modelar relações de um para muitos dentro do seu domínio.

case class Item(name: String, qty: Int)
case class Order(id: Int, items: List[Item])

object Main:
  def main(args: Array[String]): Unit =
    val order = Order(1, List(Item("pen", 2), Item("ink", 1)))
    println(order.items.map(_.qty).sum)

Compondo tipos soma

Escolhas maiores combinam escolhas menores. Uma variante de enum pode conter outro ADT, criando camadas de decisões.

enum Payment:
  case Card(last4: String)
  case Cash

enum Checkout:
  case Completed(payment: Payment)
  case Abandoned

object Main:
  def main(args: Array[String]): Unit =
    val c: Checkout = Checkout.Completed(Payment.Card("1234"))
    println(c)

Funções que compõem domínios

As operações de domínio são funções puras que recebem tipos de entrada e produzem tipos de saída. Combiná-las permite construir fluxos de trabalho.

case class Cart(total: Long)
case class Receipt(total: Long, tax: Long)

object Main:
  def checkout(c: Cart): Receipt =
    Receipt(c.total, (c.total * 0.2).toLong)

  def main(args: Array[String]): Unit =
    println(checkout(Cart(1000)))

Compondo validações

Quando cada campo é construído por um construtor inteligente, componha-os com uma compreensão for. O objeto inteiro só é criado se todas as partes forem validadas.

object V:
  def name(s: String): Option[String] = if s.nonEmpty then Some(s) else None
  def age(n: Int): Option[Int] = if n >= 0 then Some(n) else None

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

object Main:
  def make(n: String, a: Int): Option[Person] =
    for nm <- V.name(n); ag <- V.age(a) yield Person(nm, ag)

  def main(args: Array[String]): Unit =
    println(Main.make("Bob", 30))
    println(Main.make("", 30))

Reduzindo dados compostos

Agregue estruturas compostas com fold ou com map mais sum. A forma dos dados orienta o cálculo.

case class Line(price: Long, qty: Int)
case class Invoice(lines: List[Line])

object Main:
  def total(inv: Invoice): Long =
    inv.lines.foldLeft(0L)((acc, l) => acc + l.price * l.qty)

  def main(args: Array[String]): Unit =
    val inv = Invoice(List(Line(100, 2), Line(50, 4)))
    println(total(inv))

Atualizando modelos imutáveis

Componha alterações com copy, que retorna um novo valor com os campos selecionados substituídos. O original permanece intacto.

case class Account(id: Int, balance: Long)

object Main:
  def deposit(a: Account, amt: Long): Account =
    a.copy(balance = a.balance + amt)

  def main(args: Array[String]): Unit =
    val a = Account(1, 100)
    println(deposit(a, 50))

Modelando uma máquina de estados

Componha tipos soma e funções de transição para modelar uma máquina de estados na qual só existem transições legais.

enum Light:
  case Red, Green, Yellow

object Main:
  def next(l: Light): Light = l match
    case Light.Red    => Light.Green
    case Light.Green  => Light.Yellow
    case Light.Yellow => Light.Red

  def main(args: Array[String]): Unit =
    println(next(Light.Red))
    println(next(Light.Green))

Separando domínio e operações em camadas

Mantenha os tipos de dados puros e coloque o comportamento em funções ou métodos. Um modelo composto com um conjunto de transformações forma uma pequena biblioteca de domínio.

case class Temp(celsius: Double):
  def toF: Double = celsius * 9 / 5 + 32

object Main:
  def main(args: Array[String]): Unit =
    val t = Temp(25.0)
    println(t.toF)

Juntando tudo

Um modelo completo combina newtypes, produtos, somas, coleções e construção validada. O resultado é difícil de usar incorretamente e fácil de compreender.

  • Comece construindo tipos pequenos.
  • Combine-os em agregados.
  • Expresse as operações como funções puras.
case class Sku(value: String)
case class Line(sku: Sku, qty: Int)
case class Basket(lines: List[Line]):
  def count: Int = lines.map(_.qty).sum

object Main:
  def main(args: Array[String]): Unit =
    val b = Basket(List(Line(Sku("A"), 2), Line(Sku("B"), 3)))
    println(b.count)

Verificação rápida

Teste sua compreensão da composição de domínios.

Recapitulação

Você aprendeu a compor domínios.

  • Aninhe produtos e somas para modelar estruturas ricas.
  • Use coleções para relacionamentos de um para muitos.
  • Componha validações com compreensões for.
  • Atualize de forma imutável com copy.
  • Mantenha os dados puros e expresse as operações como funções.
case class User(id: Int, name: String)
case class Post(author: User, text: String)

object Main:
  def main(args: Array[String]): Unit =
    val p = Post(User(1, "Ada"), "hello")
    println(p.copy(text = "hi"))
Grátis para começar

Aprenda Scala com um tutor de IA — grátis

Escreva e execute código real no seu navegador, obtenha ajuda instantânea de um tutor de IA 24/7 e continue de onde parou na web ou no app.

Cursos
39
Aulas
143

Perguntas Frequentes

A aula “Composição de domínios” é grátis?

Sim — o texto completo de “Composição de domínios” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Scala for Backend Engineering & Functional Programming, atualize para CoddyKit PRO. O curso de Scala for Backend Engineering & Functional Programming inclui 4 aulas no total.

O que vou aprender em “Composição de domínios”?

Construa modelos maiores Você pratica Scala for Backend Engineering & Functional Programming com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Scala for Backend Engineering & Functional Programming?

Nenhuma experiência prévia é necessária. Scala for Backend Engineering & Functional Programming no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.

Quanto tempo leva a aula “Composição de domínios”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Scala for Backend Engineering & Functional Programming?

Sim. Cada aula de Scala for Backend Engineering & Functional Programming inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Modelagem com ADTs
  2. Construtores inteligentes
  3. Newtypes
  4. Composição de domínios
← Voltar para Scala for Backend Engineering & Functional Programming