Hola, soy un novato en el mundo de Kotlin. Me gusta lo que veo hasta ahora y comencé a pensar en convertir algunas de nuestras bibliotecas que usamos en nuestra aplicación de Java a Kotlin.
Estas bibliotecas están llenas de Pojos con setters, getters y clases de Builder. Ahora busqué en Google cuál es la mejor manera de implementar Builders en Kotlin, pero no tuve éxito.
2ª actualización: La pregunta es cómo escribir un patrón de diseño de Builder para un pojo simple con algunos parámetros en Kotlin. El siguiente código es mi intento escribiendo código java y luego usando el eclipse-kotlin-plugin para convertir a Kotlin.
class Car private constructor(builder:Car.Builder) {
var model:String? = null
var year:Int = 0
init {
this.model = builder.model
this.year = builder.year
}
companion object Builder {
var model:String? = null
private set
var year:Int = 0
private set
fun model(model:String):Builder {
this.model = model
return this
}
fun year(year:Int):Builder {
this.year = year
return this
}
fun build():Car {
val car = Car(this)
return car
}
}
}
design-patterns
kotlin
Keyhan
fuente
fuente
model
yyear
ser mutable? ¿Los cambias después de unaCar
creación?Respuestas:
En primer lugar, en la mayoría de los casos no es necesario usar constructores en Kotlin porque tenemos argumentos predeterminados y con nombre. Esto te permite escribir
y úsalo así:
Si quieres usar constructores, así es como puedes hacerlo:
Hacer que el constructor a
companion object
no tenga sentido porqueobject
s son singletons. En cambio, declararlo como una clase anidada (que es estática por defecto en Kotlin).Mueva las propiedades al constructor para que el objeto también se pueda instanciar de la manera regular (haga que el constructor sea privado si no debería) y use un constructor secundario que tome un constructor y delegue al constructor primario. El código se verá de la siguiente manera:
Uso:
val car = Car.Builder().model("X").build()
Este código se puede acortar adicionalmente mediante el uso de un generador DSL :
Uso:
val car = Car.build { model = "X" }
Si se requieren algunos valores y no tienen valores predeterminados, debe colocarlos en el constructor del constructor y también en el
build
método que acabamos de definir:Uso:
val car = Car.build(required = "requiredValue") { model = "X" }
fuente
Car.Builder builder = new Car.Builder();
. Sin embargo, solo la primera versión tiene una interfaz fluida, por lo que las llamadas a la segunda y tercera versión no pueden encadenarse.Un enfoque es hacer algo como lo siguiente:
Muestra de uso:
fuente
Como estoy usando la biblioteca Jackson para analizar objetos desde JSON, necesito tener un constructor vacío y no puedo tener campos opcionales. Además, todos los campos deben ser mutables. Entonces puedo usar esta buena sintaxis que hace lo mismo que el patrón Builder:
fuente
@JsonProperty
@JsonProperty
, si compila con el-parameters
interruptor.Personalmente, nunca he visto un constructor en Kotlin, pero tal vez solo soy yo.
Toda la validación que uno necesita ocurre en el
init
bloque:Aquí me tomé la libertad de adivinar que realmente no querías
model
yyear
ser cambiante. Además, esos valores predeterminados parecen no tener sentido (especialmentenull
paraname
), pero dejé uno para fines de demostración.Una opinión: El patrón de construcción utilizado en Java como un medio para vivir sin parámetros con nombre. En lenguajes con parámetros con nombre (como Kotlin o Python), es una buena práctica tener constructores con largas listas de parámetros (quizás opcionales).
fuente
@JvmOverloads
kotlinlang.org/docs/reference/…He visto muchos ejemplos que declaran diversiones adicionales como constructores. Personalmente me gusta este enfoque. Ahorre esfuerzo para escribir constructores.
Todavía no he encontrado una manera de forzar que algunos campos se inicialicen en DSL, como mostrar errores en lugar de lanzar excepciones. Avísame si alguien lo sabe.
fuente
Para una clase simple no necesitas un constructor separado. Puede hacer uso de argumentos de constructor opcionales como describió Kirill Rakhman.
Si tiene una clase más compleja, Kotlin proporciona una forma de crear constructores / DSL de estilo Groovy:
Constructores de tipo seguro
Aquí hay un ejemplo:
Ejemplo de Github: constructor / ensamblador
fuente
La gente de hoy en día debería revisar los constructores de tipo seguro de Kotlin .
Usar dicha forma de creación de objetos se verá más o menos así:
Un buen ejemplo de uso 'en acción' es el marco de trabajo vaadin-on-kotlin , que utiliza constructores de tipo seguro para ensamblar vistas y componentes .
fuente
Llego tarde a la fiesta. También me encontré con el mismo dilema si tuviera que usar el patrón Builder en el proyecto. Más tarde, después de la investigación, me di cuenta de que es absolutamente innecesario ya que Kotlin ya proporciona los argumentos nombrados y los argumentos predeterminados.
Si realmente necesita implementar, la respuesta de Kirill Rakhman es una respuesta sólida sobre cómo implementar de la manera más efectiva. Otra cosa que puede resultarle útil es https://www.baeldung.com/kotlin-builder-pattern , puede comparar y contrastar con Java y Kotlin en su implementación
fuente
Yo diría que el patrón y la implementación se mantienen más o menos igual en Kotlin. A veces puede omitirlo gracias a los valores predeterminados, pero para la creación de objetos más complicados, los constructores siguen siendo una herramienta útil que no se puede omitir.
fuente
puede usar el parámetro opcional en el ejemplo de kotlin:
luego
fuente
fuente
Implementé un patrón básico de Builder en Kotlin con el siguiente código:
Y finalmente
Java:
Kotlin:
fuente
Estaba trabajando en un proyecto de Kotlin que expuso una API consumida por clientes Java (que no puede aprovechar las construcciones del lenguaje Kotlin). Tuvimos que agregar constructores para hacerlos utilizables en Java, así que creé una anotación @Builder: https://github.com/ThinkingLogic/kotlin-builder-annotation : es básicamente un reemplazo de la anotación Lombok @Builder para Kotlin.
fuente