Именованные конструкторы Kotlin

#android #kotlin

#Android #kotlin

Вопрос:

У меня есть следующий код на языке программирования Dart

 class HttpResponse {
  final int code;
  final String? error;

  HttpResponse.ok() : code = 200; <== This functionality 
  HttpResponse.notFound()         <== This functionality
      : code = 404,
        error = 'Not found';

  String toString() {
    if (code == 200) return 'OK';
    return 'ERROR $code ${error.toUpperCase()}';
  }
}
  

Как я могу добиться этого в Kotlin, я знаю, что могу использовать статические методы, однако статические методы не предназначены для инициализации класса, есть ли способ, которым это может быть достигнуто в Kotlin?

Комментарии:

1. У Kotlin (и Java) нет именованных конструкторов. Вероятно, вы ищете статические фабричные методы.

2. Возможно, вы ищете сопутствующие объекты — они предоставят вам статические функции и будут выглядеть как ваш пример.

3. Самый простой перевод 1: 1 для вашего кода — это, вероятно, сопутствующие объекты. Для вашего конкретного примера класс enum сделает это просто отлично.

Ответ №1:

Вы ищете закрытые классы.

 sealed class HttpResponse(val code: Int, val error: String? = null) {
    
    class Ok(code: Int) : HttpResponse(code)
    
    class NotFound(code: Int, error: String?) : HttpResponse(code, error)
    
    override fun toString(): String {
        return if (code == 200) "OK"
        else "ERROR $code ${error?.toUpperCase()}"
    }
}

fun main() {
    val okResponse = HttpResponse.Ok(200)
    val notFoundResponse = HttpResponse.NotFound(404, "Not found")
}
  

Комментарии:

1. Могу ли я запретить инициализацию из HttpResponse класса, чтобы поддерживать ту же функциональность, что и исходный код из Dart?

2. По умолчанию нельзя создавать экземпляры закрытых классов. Попытка создания HttpResponse(100, "Test") выдает ошибку.

3. Но это позволяет что-то вроде HttpResponse.Ok(404) или HttpResponse.NotFound(200, "ok") чего нет в коде Dart.

4. Я не знаю Dart: ( вы хотите просто вызвать Ok(200) без HttpResponse префикса? Затем просто переместите class Ok внешнюю часть тела HttpResponse , просто поместите их в один и тот же файл, но без их вложения.

Ответ №2:

Запечатанные классы — это путь:

 import java.util.Locale.US

sealed class HttpResponse(val code: Int, val error: String?) {
  object Ok : HttpResponse(200, null)
  object NotFound : HttpResponse(404, "Not found")

  override fun toString() = when (this) {
    Ok -> "OK"
    NotFound -> "ERROR $code ${error?.uppercase(US)}"
  }
}

fun main() {
  println(HttpResponse.Ok) // OK
  println(HttpResponse.NotFound) // ERROR 404 NOT FOUND
}
  

Поскольку я не могу предложить редактирование или опубликовать комментарий, я добавляю сюда свою модифицированную версию ответа zOqvxf.

Если вы сохраняете параметры своего суперкласса неэкспонированными таким образом, нет необходимости беспокоиться об использовании HttpResponse.Ok(404) , как указано в комментарии.

Ответ №3:

Я согласен, что sealed class это предпочтительный способ, но есть другой вариант сделать конструктор закрытым и получить к нему доступ с помощью заводских методов companion object . Таким образом, вы можете получить «именованные конструкторы».

 data class HttpResponse private constructor(
    private val code: Int,
    private val error: String? = null,
) {
    companion object {
        fun ok() = HttpResponse(200)
        fun notFound() = HttpResponse(404, "Not found")
    }
}

fun main() {
    val responseOk = HttpResponse.ok()
    val responseNotFound = HttpResponse.notFound()
}