如何在创建域模型时为 String 和其他数据类型创建更具体的类型
How to create more specific types for String and other data types while creating domain models
在域建模时,我如何确保两种类型 — User
和 Place
不会互换其类型为 String
的 name
字段。
trait User {
val firstName: String
val lastName: String
}
object User {
final class Live(val firstName: String,val lastName: String) extends User
def apply(firstName: String, lastName: String): User = new Live(firstName, lastName)
}
trait Place {
val name: String
}
object Place {
final class Live(val name: String) extends Place
def apply(name: String): Place = new Live(name)
}
val a = User("Tushar", "Mathur")
val b = Place("Mumbai")
val c = Place(a.firstName)
// How do I disable this ^
Scala 支持此功能,如下例所示。有一些库可以减少样板代码,但我只展示最简单的选项:
// define more restrictive String-like types. AnyVal construction can be free from
// overhead with some caveats.
case class UserName(name: String) extends AnyVal
case class PlaceName(name: String) extends AnyVal
// define your classes (I've changed them a bit for brevity):
case class User(name: UserName)
case class Place(name: PlaceName)
// implicits for convenience of construction:
implicit val strToUserName = UserName(_)
implicit val strToPlaceName = PlaceName(_)
// test it out:
scala> val u = User("user")
u: User = User(UserName(user))
scala> val p = Place("place")
p: Place = Place(PlaceName(place))
// as expected you CAN'T do this:
scala> User(p.name)
<console>:17: error: type mismatch;
found : PlaceName
required: UserName
User(p.name)
^
// comparison test:
scala> p.name == u.name
<console>:16: warning: comparing case class values of types PlaceName and UserName using `==' will always yield false
p.name == u.name
^
res3: Boolean = false
// you can still get at the string value:
scala> p.name
res6: PlaceName = PlaceName(place)
scala> p.name.name
res5: String = place
在域建模时,我如何确保两种类型 — User
和 Place
不会互换其类型为 String
的 name
字段。
trait User {
val firstName: String
val lastName: String
}
object User {
final class Live(val firstName: String,val lastName: String) extends User
def apply(firstName: String, lastName: String): User = new Live(firstName, lastName)
}
trait Place {
val name: String
}
object Place {
final class Live(val name: String) extends Place
def apply(name: String): Place = new Live(name)
}
val a = User("Tushar", "Mathur")
val b = Place("Mumbai")
val c = Place(a.firstName)
// How do I disable this ^
Scala 支持此功能,如下例所示。有一些库可以减少样板代码,但我只展示最简单的选项:
// define more restrictive String-like types. AnyVal construction can be free from
// overhead with some caveats.
case class UserName(name: String) extends AnyVal
case class PlaceName(name: String) extends AnyVal
// define your classes (I've changed them a bit for brevity):
case class User(name: UserName)
case class Place(name: PlaceName)
// implicits for convenience of construction:
implicit val strToUserName = UserName(_)
implicit val strToPlaceName = PlaceName(_)
// test it out:
scala> val u = User("user")
u: User = User(UserName(user))
scala> val p = Place("place")
p: Place = Place(PlaceName(place))
// as expected you CAN'T do this:
scala> User(p.name)
<console>:17: error: type mismatch;
found : PlaceName
required: UserName
User(p.name)
^
// comparison test:
scala> p.name == u.name
<console>:16: warning: comparing case class values of types PlaceName and UserName using `==' will always yield false
p.name == u.name
^
res3: Boolean = false
// you can still get at the string value:
scala> p.name
res6: PlaceName = PlaceName(place)
scala> p.name.name
res5: String = place