【问题标题】:Overload constructor with different param type具有不同参数类型的重载构造函数
【发布时间】:2013-04-15 12:32:34
【问题描述】:

我知道我们可以在 Scala 中重载类构造函数,如下所示-

class Foo(x: Int, z: String) { 
  def this(z: String) = this(0, z);   
}

但是如何重载一个具有以下两种完全不同类型的参数的类(假设我可以通过 name 或数字 id 来识别用户)

class User(userId: Int) {
  ...
}

class User(userName: String) {
  ...
}

【问题讨论】:

  • 这两种情况没有真正的区别;两者都没有过载冲突。我不确定是什么没有做您想要或期望的事情,或者,真的,您遇到了什么确切的问题。

标签: scala constructor-overloading


【解决方案1】:

(假设我可以通过名称或数字 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 的想法,以防用户可以被其他构造识别。

【讨论】:

  • 非常感谢您花时间回复。第一种方法的问题是将解决方案限制在两种类型,不能扩展到更多类型。但我绝对赞成第二种方法。
【解决方案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
  }

}

【讨论】:

    【解决方案3】:

    你可以这样做:

    class User private() {
      def this( userName: String ) = { this(); ??? }
      def this( userId: Int ) = { this(); ??? }
    }
    

    private 关键字将无参数构造函数设为私有。这意味着您的其他辅助构造函数不需要将任何内容传递给主构造函数 (有效地使两个辅助构造函数独立),但调用者仍然无法在不传递任何参数的情况下实例化该类。 请注意,当您的类具有要从构造函数参数初始化的 val 时,使用此模式可能会很棘手。

    【讨论】:

    • 绝妙绝招!它运作良好。如果 User 是一个案例类怎么办?
    猜你喜欢
    • 2010-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-26
    相关资源
    最近更新 更多