我知道我们可以在 Scala 中重载类构造函数,如下所示 -
class Foo(x: Int, z: String) {
def this(z: String) = this(0, z);
}
但是我怎样才能重载一个具有两种完全不同类型的参数的类,如下所示(想象我可以通过名称或数字id来识别用户)
class User(userId: Int) {
...
}
class User(userName: String) {
...
}
我知道我们可以在 Scala 中重载类构造函数,如下所示 -
class Foo(x: Int, z: String) {
def this(z: String) = this(0, z);
}
但是我怎样才能重载一个具有两种完全不同类型的参数的类,如下所示(想象我可以通过名称或数字id来识别用户)
class User(userId: Int) {
...
}
class User(userName: String) {
...
}
(假设我可以通过名称或数字 id 来识别用户)
你几乎肯定不想通过在你的类中使用可选字段来做到这一点。相反,您应该将用户以各种方式识别的事实编码到程序的类型和结构中。
一种方法是使用 Scala 的内置Either
类型对用户标识符进行编码:
class User private(identifier : Either[String, Int]) {
def this(id : Int) = this(Right(id))
def this(name : String) = this(Left(name))
}
但是,您可能还希望使用户标识符的性质更加明确,并将其编码为您自己的代数数据类型:
trait UserIdentifier
object UserIdentifier {
case class ById(id : Int) extends UserIdentifier
case class ByName(name : String) extends UserIdentifier
}
class User(id : UserIdentifier) {
def this(id : Int) = this(UserIdentifier.ById(id))
def this(name : String) = this(UserIdentifier.ByName(name))
}
通过这种方式,您可以防止出现问题,例如有人试图在用户上查找由 id 标识的名称。第二种方法还允许您UserIdentifier
在将来扩展 a 的想法,以防用户可以被其他构造识别。
或者,您可以这样做
object User {
def apply(userId: Int) = new UserI(userId)
def apply(name: String) = new UserS(name)
class UserI(userId: Int)
class UserS(userName: String)
}
并以这种方式使用它:
val u1 = User(1)
val u2 = User("a")
如果你有很多共同的逻辑,你可以把它放到一个共同的抽象类中
object User {
def apply(userId: Int) = new UserI(userId)
def apply(name: String) = new UserS(name)
class UserI(userId: Int) extends AUser
class UserS(userName: String) extends AUser
abstract class AUser{
// common logic for both classes
}
}
你可以这样做:
class User private() {
def this( userName: String ) = { this(); ??? }
def this( userId: Int ) = { this(); ??? }
}
关键字使private
无参数构造函数私有。这意味着您的其他辅助构造函数不需要向主构造函数传递任何内容(有效地使两个辅助构造函数独立),但调用者仍然无法在不传递任何参数的情况下实例化该类。请注意,当您的类具有要从 construtors 参数初始化的 val 时,使用此模式可能会很棘手。