Предварительная обработка параметров конструктора класса case без повторения списка аргументов
У меня есть этот класс с большим количеством параметров:
case class Document(id:String, title:String, ...12 more params.. , keywords: Seq[String])
Для определенных параметров мне нужно выполнить очистку строки (обрезку и т. Д.) Перед созданием объекта.
Я знаю, что мог бы добавить объект-компаньон с функцией apply, но последнее, что я хочу, это написать список параметров ДВАЖДЫ в моем коде (конструктор класса case и объект-компаньон apply).
Предоставляет ли Scala что-нибудь, чтобы помочь мне в этом?
2 ответа
Мои общие рекомендации:
Ваша цель (предварительная обработка данных) - идеальный вариант использования сопутствующего объекта - так что, возможно, это самое идиоматическое решение, несмотря на шаблон.
Если число параметров класса case велико, шаблон компоновщика определенно помогает, так как вам не нужно запоминать порядок параметров, и ваша IDE может помочь вам с вызовом функций-членов компоновщика. Использование именованных аргументов для конструктора класса case также позволяет использовать случайный порядок аргументов, но, насколько мне известно, в именованных аргументах нет автодополнения IDE =>, что делает класс построителя несколько более удобным. Однако использование класса построителя поднимает вопрос о том, как бороться с применением спецификации определенных аргументов - простое решение может вызвать ошибки во время выполнения; Типобезопасное решение немного более многословно. В этом отношении класс case с аргументами по умолчанию более элегантен.
Существует также это решение: ввести дополнительный флаг preprocessed
с аргументом по умолчанию false
, Всякий раз, когда вы хотите использовать экземпляр val d: Document
, ты звонишь d.preprocess()
реализовано с помощью метода копирования класса case (чтобы избежать повторного ввода всех аргументов):
case class Document(id: String, title: String, keywords: Seq[String], preprocessed: Boolean = false) {
def preprocess() = if (preprocessed) this else {
this.copy(title = title.trim, preprocessed = true) // or whatever you want to do
}
}
Но: вы не можете предотвратить инициализацию клиента preprocessed
установлен в true
,
Другим вариантом будет сделать некоторые из ваших параметров private val
и выставить соответствующий геттер для предварительно обработанных данных:
case class Document(id: String, title: String, private val _keywords: Seq[String]) {
val keywords = _keywords.map(kw => kw.trim)
}
Но: сопоставление с образцом и по умолчанию toString
реализация не даст вам совсем то, что вы хотите...
После изменения контекста в течение получаса я посмотрел на эту проблему свежим взглядом и придумал следующее:
case class Document(id: String, title: String, var keywords: Seq[String]) {
keywords = keywords.map(kw => kw.trim)
}
Я просто делаю аргумент изменяемым добавлением var
и очистка данных в теле класса.
Хорошо, я знаю, мои данные больше не являются неизменными, и Мартин Одерски, вероятно, убьет котенка, увидев это, но эй.. Мне удалось сделать то, что я хочу, добавив 3 символа. Я называю это победой:)