超載構造我知道,我們可以在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) {
...
}
Alternativelly無論是識別用戶,你可以做到這一點
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
關鍵字使no-arg構造函數爲private。這意味着你的其他次構造函數不需要傳遞任何東西給主構造函數 (有效地使兩個次構造函數獨立),但是調用者在不傳遞任何參數的情況下仍然不能實例化類。 請注意,當您的類有vals從construtors參數進行初始化時,此模式可能會非常棘手。
好戲!它運作良好。如果* User *是案例課程怎麼辦? –
(想象一下,我可以通過名稱或數字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
的想法,以防用戶可以通過其他構造識別。
非常感謝您花時間回覆。第一種方法限制TWO類型解決方案的問題無法針對更多類型進行擴展。但我絕對投票支持第二種方法。 –
這兩種情況之間沒有真正的區別;沒有超載衝突。我不確定什麼不是你想要的或者期望的,或者真的,你遇到了什麼確切的問題。 –