2013-04-15 4 views
1

Я знаю, что мы можем перегрузить конструктор класса в Scala следующего образом-конструктор перегрузки с различным типом паров

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

Но как я могу перегрузить класс, которые имеют две совершенно разные типов параметров, как показано ниже (представьте себе, что я может идентифицировать пользователя, либо именем или цифровой ид)

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 закрытым. Это означает, что другим вспомогательным конструкторам не нужно передавать что-либо основному конструктору (что делает два независимых конструктора независимыми), но вызывающие абоненты все еще не могут создать экземпляр класса с передачей любого параметра. Обратите внимание, что этот шаблон может быть сложно использовать, когда ваш класс имеет vals для инициализации из параметров construtors.

+0

Отличный трюк! Он работал хорошо. Что делать, если * Пользователь * является классом case? –

2

(представьте себе, что я могу идентифицировать пользователя по имени или числовым идентификатором)

Вы почти наверняка не хотите, чтобы это сделать, имея дополнительные поля в классе. Скорее, вы должны кодировать тот факт, что пользователь по-разному идентифицирует типы и структуру вашей программы.

Один из способов сделать это, чтобы закодировать идентификатор пользователя, используя 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)) 
} 

делая это таким образом, предотвратить такие проблемы, как кто-то пытается искать имя на пользователя, который идентифицируется идентификатором вместо этого. Второй подход также позволяет расширить идею UserIdentifier в будущем, если пользователь может быть идентифицирован какой-либо другой конструкцией.

+0

Большое спасибо за то, что нашли время ответить. Проблема с первым подходом ограничивает решение для TWO-типов, не может быть расширена для большего количества типов. Но я определенно проголосую за второй подход. –

Смежные вопросы