如何实现scala子类型的流畅接口?



我可以用以下方式实现具有流畅接口的嵌套类:

class Animal(name: String, props: Map[String, Any]) {
def properties: Map[String, Any] = Map("name" -> name) ++ props
def withAge(age: Int): Animal = new Animal(name, props.updated("age", age)) // can't use built-in copy
}
case class Cat(name: String, lives: Int, props: Map[String, Any]) extends Animal(name, props) {
override def properties: Map[String, Any] = Map("name" -> name, "lives" -> lives) ++ props
override def withAge(age: Int): Cat = Cat(name, lives, props.updated("age", age))
}

然而,我对此远不满意。有很多重复,即使我使用继承,我也没有重用任何代码。我尝试使用this.type作为返回类型,甚至使用zio-prelude子类型功能,但持续存在的问题是,在某些时候,子类不能正确识别。

有没有更好的方法来做到这一点,没有重复和利用scala的特性?

理想情况下,我想要这样的东西

case class Animal(name: String, props: Map[String, Any]) {
def properties: Map[String, Any] = Map("name" -> name) ++ props
def withAge(age: Int): this.type = copy(props = props.updated("age", age))
}
final case class Cat(name: String, lives: Int, props: Map[String, Any]) extends Animal(name, props + ("lives" -> lives))

以避免重复发生。当然,下面的代码不能编译。

val myCat: Cat = Cat("murzic", 9, Map()).withAge(4)
package animalworld
import scala.collection.mutable
class Builder(val properties: mutable.HashMap[String, Any]) {
def this() = this(mutable.HashMap.empty)
def withName(name: String): Builder = {
properties.put("name", name)
this
}
def withAge(age: Int): Builder = {
properties.put("age", age)
this
}
def setProperty(key: String, value: Any): Builder = {
properties.put(key, value)
this
}
def build[A <: Animal](implicit buildable: Buildable[A]): A =
buildable.build(this)
}
package animalworld
trait Buildable[A <: Animal] {
def build(builder: Builder): A
}
package animalworld
import scala.collection.mutable
class Animal protected (val name: String, val properties: Map[String, Any]) {
def toBuilder: Builder = new Builder(mutable.HashMap.from(properties))
}
object Animal {
implicit val animalBuildable: Buildable[Animal] = { builder =>
new Animal(
builder.properties("name").asInstanceOf[String],
Map.from(builder.properties)
)
}
}
package animalworld
class Cat protected (
override val name: String,
val lives: Int,
override val properties: Map[String, Any]
) extends Animal(name, properties)
object Cat {
implicit val catBuildable: Buildable[Cat] = { builder =>
new Cat(
builder.properties("name").asInstanceOf[String],
builder.properties("lives").asInstanceOf[Int],
Map.from(builder.properties)
)
}
}
package animalworld
object Main extends App {
val animal1 = new Builder().withName("tim-tim").build[Animal]
val cat1 = animal1.toBuilder.withAge(10).setProperty("lives", 9).build[Cat]
println(animal1.name)
// tim-tim
println(animal1.properties)
// Map(name -> tim-tim)
println(cat1.name)
// tim-tim
println(cat1.lives)
// 9
println(cat1.properties)
// Map(name -> tim-tim, lives -> 9, age -> 10)
}

相关内容

  • 没有找到相关文章

最新更新