Составные предметные области
Создавайте более крупные модели
«Составные предметные области» — бесплатный урок Scala for Backend Engineering & Functional Programming на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Scala for Backend Engineering & Functional Programming, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Scala for Backend Engineering & Functional Programming содержит 4 уроков всего.
Создание более крупных моделей
Предметные области строятся из небольших частей. Композиция предметных областей означает объединение хорошо смоделированных ADT, новых типов и проверенных значений в более крупные, но по-прежнему корректные структуры.
- Небольшие специализированные типы объединяются в более крупные.
- Каждая часть сохраняет свои инварианты.
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)))Вложенные произведения
Составляйте типы-произведения, вкладывая классы вариантов. Каждый уровень добавляет структуру, сохраняя читаемость.
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)Композиция с коллекциями
Используйте List, Map и Set, чтобы моделировать отношения «один ко многим» внутри предметной области.
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)Композиция типов-сумм
Более крупные варианты объединяют более мелкие. Вариант перечисления сам может содержать другой ADT, создавая несколько уровней решений.
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)Функции, составляющие предметные области
Операции предметной области — это чистые функции, преобразующие типы входных данных в типы выходных данных. Их композиция образует рабочие процессы.
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)))Композиция проверок
Если каждое поле создаётся с помощью интеллектуального конструктора, объединяйте их в выражении for. Весь объект будет создан только в том случае, если проверку пройдёт каждая его часть.
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))Свёртка составных данных
Агрегируйте составные структуры с помощью fold или комбинации map и sum. Форма данных подсказывает, как выполнять вычисление.
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))Обновление неизменяемых моделей
Составляйте изменения с помощью copy: этот метод возвращает новое значение, в котором указанные поля заменены. Исходное значение остаётся без изменений.
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))Моделирование конечного автомата
Сочетайте типы-суммы и функции переходов, чтобы смоделировать конечный автомат, в котором существуют только допустимые переходы.
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))Разделение предметной области и операций на уровни
Держите типы данных чистыми, а поведение размещайте в функциях или методах. Составная модель и набор преобразований образуют небольшую библиотеку предметной области.
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)Объединение всех частей
Полная модель объединяет новые типы, произведения, суммы, коллекции и создание с проверкой. Такую модель трудно использовать неправильно и легко анализировать.
- Сначала создавайте небольшие типы.
- Объединяйте их в агрегаты.
- Представляйте операции в виде чистых функций.
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)Быстрая проверка
Проверьте, насколько хорошо Вы поняли композицию предметных областей.
Итоги
Вы научились составлять предметные области.
- Вкладывайте произведения и суммы, чтобы моделировать сложные структуры.
- Используйте коллекции для отношений «один ко многим».
- Составляйте проверки с помощью выражений
for. - Обновляйте значения неизменяемым способом с помощью
copy. - Оставляйте данные чистыми, а операции выражайте функциями.
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"))Изучай Scala с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 39
- Уроки
- 143
Часто задаваемые вопросы
Урок «Составные предметные области» бесплатный?
Да — полный текст урока «Составные предметные области» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Scala for Backend Engineering & Functional Programming, подпишись на CoddyKit PRO. Курс Scala for Backend Engineering & Functional Programming содержит 4 уроков всего.
Чему я научусь в уроке «Составные предметные области»?
Создавайте более крупные модели Ты практикуешь Scala for Backend Engineering & Functional Programming с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Scala for Backend Engineering & Functional Programming?
Предыдущий опыт не требуется. Scala for Backend Engineering & Functional Programming на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Составные предметные области»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Scala for Backend Engineering & Functional Programming?
Да. Каждый урок Scala for Backend Engineering & Functional Programming включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Моделирование с помощью ADT
- Умные конструкторы
- Newtype-типы
- Составные предметные области