Я изучаю кейс-классы Scala и шаблоны проектирования. С этой целью я создал приведенный ниже пример, который, как мне кажется, является довольно вероятным сценарием при работе с данными типа Json. Я знаю, что существуют библиотеки, которые делают это, но я делаю это вручную, чтобы изучить подходы Scala к решению проблем, так как использование библиотеки не поможет мне учиться.
Основное улучшение дизайна, которое я хочу сделать, — это абстрагирование общего кода.
Предположим, моя кодовая база состоит из множества классов case, где каждый класс case сериализуем:
trait Base {
def serialize(): String
}
trait Animal extends Base
trait Mammal extends Animal
trait Reptile extends Animal
case class Lizard(name: String, tail: Boolean) extends Reptile {
def serialize(): String = s"""{name: $name, tail: $tail}"""
}
case class Cat(name: String, age: Int) extends Mammal {
def serialize(): String = s"""{name: $name, age: $age}"""
}
case class Fish(species: String) extends Animal {
def serialize(): String = s"""{species: $species}"""
}
case class Pets(group_name: String, cat: Option[Cat] = None, lizard: Option[Lizard] = None, fish: Fish) extends Base {
def serialize(): String = {
// cat and lizard serialize in a similar fashion
val cat_object = cat match {
case Some(c) => s"""cats: ${c.serialize()}"""
case _ => ""
}
val lizard_object = lizard match {
case Some(d) => s"""lizards: ${d.serialize()}"""
case _ => ""
}
// fish serializes in a different way as it is not an option
val fish_object = s"""fish: ${fish.serialize()}"""
s"""{$lizard_object, $cat_object, $fish_object}"""
}
}
val bob = Cat("Bob", 42)
val jill = Lizard("Jill", true)
val pets = Pets("my group", Some(bob), Some(jill), Fish("goldfish")).serialize()
println(pets)
}
Теперь здесь есть повторяющийся шаблон:
В Pets при сериализации я в основном просматриваю каждую пару (ключ, значение) (кроме group_name) в списке параметров и делаю следующее:
ключ: значение.serialize()
Сейчас форму значения не знаю, может быть вариант как в примере. Кроме того, предположим, что у меня есть много классов, таких как Pets. В этом случае мне пришлось бы вручную писать много совпадений с шаблоном для каждого аргумента, где это необходимо, различая String, Int, Option [String] и т. д. Был бы способ абстрагироваться от этой сериализуемой операции, чтобы, если у меня есть много классов case как и с домашними животными, я могу просто запустить одну функцию и получить правильный результат.
Я задал связанный вопрос здесь о получении объявленного поля из классов случаев, но кажется, что этот способ не является безопасным для типов и может создать проблемы позже, если я добавлю больше пользовательских классов случаев:
https://stackoverflow.com/questions/62662417/how-to-get-case-class-parameter-key-value-pairs