Last active
May 20, 2022 00:06
-
-
Save rinotc/3e56f67a7ee938f4744025733ce1923c to your computer and use it in GitHub Desktop.
Generalized type constrains を使ったtype-safe builder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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