Skip to content

Instantly share code, notes, and snippets.

@rinotc
Last active May 20, 2022 00:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rinotc/3e56f67a7ee938f4744025733ce1923c to your computer and use it in GitHub Desktop.
Save rinotc/3e56f67a7ee938f4744025733ce1923c to your computer and use it in GitHub Desktop.
Generalized type constrains を使ったtype-safe builder
class Person(
val firstName: String,
val lastName: String,
val age: Int
) {
protected def this() = this("", "", 0)
protected def this(pb: Person.Builder[_]) = this(pb.firstName, pb.lastName, pb.age)
}
object Person {
sealed trait BuildStep
sealed trait HasFirstName extends BuildStep
sealed trait HasLastName extends BuildStep
class Builder[PassedStep <: BuildStep] private (
var firstName: String,
var lastName: String,
var age: Int
) {
protected def this() = this("", "", 0)
protected def this(pb: Builder[_]) = this(
pb.firstName,
pb.lastName,
pb.age
)
def setFirstName(firstName: String): Builder[HasFirstName] = {
this.firstName = firstName
new Builder[HasFirstName](this)
}
def setLastName(lastName: String)(implicit ev: PassedStep =:= HasFirstName): Builder[HasLastName] = {
this.lastName = lastName
new Builder[HasLastName](this)
}
def setAge(age: Int): Builder[PassedStep] = {
this.age = age
this
}
def build(implicit ev: PassedStep =:= HasLastName): Person = {
new Person(firstName, lastName, age)
}
}
object Builder {
def apply() = new Builder[BuildStep]()
}
}
object Main {
def main(args: Array[String]): Unit = {
val person = Person
.Builder()
.setFirstName("太郎")
.setLastName("田中")
.setAge(33)
.build
println(s"Person: ${person.lastName} ${person.firstName}, ${person.age}歳")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment