2014-10-30 2 views
1

У меня есть класс в Scala, как это:По умолчанию застройщик класса

abstract class ErrorMessages(val message: String, val publicMessage: String, val objectData: Option[Object], val backtrace: Exception) 

что я использую бабло как суб классы, например

case class MyError(override val message: String, override val publicMessage: String, override val objectData: Option[Object], override val backtrace: Exception) extends ErrorMessages(message, publicMessage, objectData, backtrace) 

Мой Quested здесь я могу сделать последний вещь более легкая как case class MyError(...) extends ErrorMessages(...) или симулятор для краткости кода, необходимый для создания нового экземпляра моего errpr.

+0

Изменить 'abstract class ErrorMessages' на' trait ErrorMessages', а затем вызвать 'case class MyError (message: String, ...) extends ErrorMessages' –

ответ

0

Вы можете агрегировать все параметры конструктора в один класс case, а затем передать этот класс case в конструктор. Например:

case class ErrorData(message:String, publicMessage:String, objectData:Option[Object], backtrace:Exception) 

abstract class ErrorMessages(data:ErrorData) 

case class MyError(data:ErrorData) extends ErrorMessages(data) 

Это, вероятно, нуждается в некоторой доработке. Например, вы можете захотеть сделать компоненты ErrorData доступны через ErrorMessages, а также:

abstract class ErrorMessages(data:ErrorData) { 
    def message:String = data.message 
    def publicMessage:String = data.publicMessage 
    // ... 
} 

Таким образом, MyError также наследует методы, позволяющие прямой доступ к message, publicMessage, objectData и т.д. Эффективно, то существование ErrorData скрыто во внешнем мире. Это всего лишь утилита для создания экземпляров подтипов ErrorMessages. Это, однако, также потребует от вас повторного введения модификаторов override из вашего примера.

Вот альтернативный дизайн:

Может быть, вы также хотите, чтобы пропустить конструктор вообще. Вы можете сделать это, сделав компоненты анкеты ErrorMessages. Пример:

abstract class ErrorMessages { // could also be a trait now 
    def message:String 
    def publicMessage:String 
    def objectData:Option[Object] 
    // ... 
} 

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

Наконец, вы можете быть творческим и объединить эти стратегии. Возможно, вы не хотите интегрировать все параметры конструктора в один класс большого класса, но только некоторые из них, которые подходят друг к другу тематически. Когда у вас много параметров конструктора, иногда это может быть признаком того, что вам нужны более интегративные типы данных. Пример:

case class Message(internalText:String, publicText:String) 
case class ErrorOrigin(objectData:Option[Object], backtrace:Exception) 

trait ErrorMessages { // you can use the constructor approach or abstract members, as shown here 
    def message:Message 
    def origin:ErrorOrigin 

    def internalMessageText = message internalText 
    def publicMessageText = message publicText 
    def objectData = origin objectData 
    def backtrace = origin backTrace 
} 

case class MyErrorMessage(message:Message, origin:ErrorOrigin) extends ErrorMessages 

Или вы можете смешать оба пути вверх:

abstract class ErrorMessages(val origin:ErrorOrigin) { 
    def message:Message 

    def internalMessageText = message internalText 
    // ... 
} 

case class MyErrorMessage(message:Message, override val origin:ErrorOrigin) 

Не уверен, если это разделение хорошо для вас, или если эти имена типов и члены имеют смысл в вашем случае. Но я надеюсь, что вы видите картину: есть некоторые заметные альтернативы, вы можете поиграть с ними и выбрать то, что подходит лучше всего.

Однако нельзя исключить передачу параметров наследуемого конструктора. Было бы неплохо иметь литерал ..., где компилятор Scala будет соответствовать всем параметрам конструктора суперпотока, которые имеют те же имена, что и в подтипе, но такой функции не существует.

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