0Pricing
Scala for Backend Engineering & Functional Programming · Lekcja

Komponowanie domen

Budowanie większych modeli

Komponowanie domen to bezpłatna lekcja Scala for Backend Engineering & Functional Programming na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Scala for Backend Engineering & Functional Programming, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Scala for Backend Engineering & Functional Programming zawiera 4 lekcji w sumie.

Tworzenie większych modeli

Rzeczywiste domeny składają się z mniejszych elementów. Komponowanie domen oznacza łączenie dobrze zamodelowanych ADT, newtype’ów i zweryfikowanych wartości w większe, nadal poprawne struktury.

  • Małe, wyspecjalizowane typy składają się w większe.
  • Każdy element zachowuje własne niezmienniki.
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)))

Zagnieżdżanie produktów

Typy produktowe komponuje się przez zagnieżdżanie klas przypadków. Każdy poziom dodaje strukturę, zachowując czytelność.

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)

Komponowanie z kolekcjami

Używaj List, Map i Set do modelowania relacji jeden-do-wielu w obrębie domeny.

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)

Komponowanie typów sum

Większe zestawy wyborów łączą mniejsze. Wariant enuma może sam zawierać inny ADT, tworząc kolejne warstwy decyzji.

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)

Funkcje komponujące domeny

Operacje domenowe to czyste funkcje przekształcające typy wejściowe w typy wyjściowe. Ich komponowanie pozwala budować przepływy pracy.

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)))

Komponowanie walidacji

Gdy każde pole jest tworzone przez smart constructor, połącz je za pomocą wyrażenia for. Cały obiekt zostanie utworzony tylko wtedy, gdy każda część przejdzie walidację.

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))

Składanie danych złożonych

Agreguj złożone struktury za pomocą fold lub map oraz sum. Kształt danych wyznacza sposób obliczeń.

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))

Aktualizowanie niezmiennych modeli

Komponuj zmiany za pomocą copy, które zwraca nową wartość z zastąpionymi wybranymi polami. Oryginał pozostaje niezmieniony.

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))

Modelowanie maszyny stanów

Połącz typy sum i funkcje przejść, aby zamodelować maszynę stanów, w której istnieją tylko dozwolone przejścia.

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))

Rozdzielanie domeny i operacji na warstwy

Utrzymuj typy danych jako czyste, a zachowanie umieszczaj w funkcjach lub metodach. Połączony model wraz z zestawem transformacji tworzy niewielką bibliotekę domenową.

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)

Złożenie wszystkiego w całość

Kompletny model łączy newtype’y, produkty, sumy, kolekcje i tworzenie z walidacją. Rezultat jest trudny do niewłaściwego użycia i łatwy do przeanalizowania.

  • Najpierw twórz małe typy.
  • Łącz je w agregaty.
  • Wyrażaj operacje jako czyste funkcje.
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)

Szybkie sprawdzenie

Sprawdź, czy rozumiesz komponowanie domen.

Podsumowanie

Nauczyłeś się komponować domeny.

  • Zagnieżdżaj produkty i sumy, aby modelować rozbudowane struktury.
  • Używaj kolekcji do relacji jeden-do-wielu.
  • Komponuj walidacje za pomocą wyrażeń for.
  • Aktualizuj dane w sposób niezmienny za pomocą copy.
  • Utrzymuj dane jako czyste i wyrażaj operacje za pomocą funkcji.
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"))

Często zadawane pytania

Czy lekcja „Komponowanie domen” jest bezpłatna?

Tak — pełny tekst „Komponowanie domen” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Scala for Backend Engineering & Functional Programming, przejdź na CoddyKit PRO. Kurs Scala for Backend Engineering & Functional Programming zawiera 4 lekcji w sumie.

Co nauczysz się w „Komponowanie domen”?

Budowanie większych modeli Ćwiczysz Scala for Backend Engineering & Functional Programming z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Scala for Backend Engineering & Functional Programming?

Nie wymagamy żadnego doświadczenia. Scala for Backend Engineering & Functional Programming w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Komponowanie domen”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Scala for Backend Engineering & Functional Programming?

Tak. Każda lekcja Scala for Backend Engineering & Functional Programming zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Modelowanie za pomocą ADT
  2. Inteligentne konstruktory
  3. Newtype
  4. Komponowanie domen
← Powrót do Scala for Backend Engineering & Functional Programming