2013-04-15 401 views
1

超載構造我知道,我們可以在Scala中重載類的構造函數如下 -不同的參數類型

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

但我怎麼能超載具有兩種完全不同類型的如下參數類(想象我可以通過或數字ID

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

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

這兩種情況之間沒有真正的區別;沒有超載衝突。我不確定什麼不是你想要的或者期望的,或者真的,你遇到了什麼確切的問題。 –

回答

2

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 
    } 

} 
1

你可以這樣做:

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

private關鍵字使no-arg構造函數爲private。這意味着你的其他次構造函數不需要傳遞任何東西給主構造函數 (有效地使兩個次構造函數獨立),但是調用者在不傳遞任何參數的情況下仍然不能實例化類。 請注意,當您的類有vals從construtors參數進行初始化時,此模式可能會非常棘手。

+0

好戲!它運作良好。如果* User *是案例課程怎麼辦? –

2

(想象一下,我可以通過名稱或數字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的想法,以防用戶可以通過其他構造識別。

+0

非常感謝您花時間回覆。第一種方法限制TWO類型解決方案的問題無法針對更多類型進行擴展。但我絕對投票支持第二種方法。 –

相關問題