Класс случая Scala, обогащенный абстрактным компонентом (Cake Pattern)
Мы используем шаблон торта для абстрагирования компонентов (DB, Mock) с аннотацией собственного типа, которые вводятся при вызове верхнего уровня.
В одном случае класс мы хотим быть в состоянии улучшить его поведение, расширяя общую черту. Но как это сделать, если мы хотим, чтобы этот case-класс вызывал абстрактный компонент? Рефакторинг класса case как абстрактного приведет к удалению всей реализации apply, unapply, copy ... Вещи, которые нам нужны для сопоставления базы данных и модели (например, с помощью Slick).
Вот пример, представляющий растения в некоторых блоках как ресурсы, принадлежащие учетной записи:
trait Resource {
def getAccount: Future[Account]
}
case class Account(id: Int)
case class Block(id: Int, name:String, accountId: Int) extends Resource
case class Plant(id: Int, name: String, blockId: Int) extends Resource {
this: PlantDBComponent =>
override def getAccount: Future[Account] = plantDB.getAccount(this)
}
trait PlantDBComponent {
def plantDB: PlantDB
trait PlantDB {
def getAccount(plant: Plant): Future[Account]
}
}
trait SlickPlantDBComponent {
def blockDB = SlickPlantDB()
trait SlickPlantDB extends PlantDB {
def getAccount(block: Block): Future[Account] = {
val q = for {
block <- BlockTable if block.id === plant.blockId
account <- AccountTable if account.id === block.accountId
} yield account
db.run(q.result.head)
}
}
}
Любая идея о том, как это сделать без переопределения всех шаблонов класса дела? Добавление getAccount в сопутствующий объект Resource с сопоставлением с шаблоном case не решит проблему
1 ответ
Мы решили реализовать ResourceService, который в соответствии с типом ресурса возвращает учетную запись, к которой принадлежит ресурс.
Вот компонент черты:
trait ResourceServiceComponent {
val resourceService: ResourceService
trait ResourceService {
def getAccount(resource: Resource): Future[Account] = {
resource match {
case plant: Plant => blockDB.getAccount(plant.blockId)
case ...
}
}
}
}