我知道我们可以在Scala中重载类构造函数,如下所示 -
class Foo(x: Int, z: String) {
def this(z: String) = this(0, z);
}
但是如何重载具有两个完全不同类型的参数的类(如下所示)(假设我可以通过名称或数字 id 来识别用户)< / p>
class User(userId: Int) {
...
}
class User(userName: String) {
...
}
答案 0 :(得分:3)
(想象一下,我可以通过名字或数字ID识别用户)
您几乎肯定不希望通过在您的班级中添加可选字段来实现此目的。相反,您应该编码这样一个事实,即用户可以通过各种方式识别您的程序的类型和结构。
执行此操作的一种方法是使用Scala的内置Either
类型对用户标识符进行编码:
class User private(identifier : Either[String, Int]) {
def this(id : Int) = this(Right(id))
def this(name : String) = this(Left(name))
}
但是,您可能还希望将用户标识符的性质更加明确,并将其编码为您自己的Algebraic data type:
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
的概念,以防用户可以通过其他构造进行识别。
答案 1 :(得分:2)
另外,你可以这样做
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
}
}
答案 2 :(得分:1)
你可以这样做:
class User private() {
def this( userName: String ) = { this(); ??? }
def this( userId: Int ) = { this(); ??? }
}
private
关键字使no-arg构造函数变为私有。这意味着您的其他辅助构造函数不需要将任何内容传递给主构造函数
(有效地使两个辅助构造函数无关),但调用者仍然无法在没有传递任何参数的情况下实例化该类。
请注意,当您的类具有从construtors参数初始化的val时,此模式可能很难使用。