Padrões de Projeto em Kotlin: nível avançado com exemplos

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Padrões de Design em Kotlin com Exemplos: Nível Avançado

No nível inicial, desenvolvedores dominam padrões clássicos: Singleton, Factory, Observer. No entanto, ao construir sistemas complexos e escaláveis, é necessário um ajuste arquitetural mais sutil. Neste artigo, analisaremos quatro padrões de design avançados em Kotlin: Composite, Visitor, State e Bridge. Cada padrão será ilustrado com um exemplo prático de código e uma explicação de quando aplicá-lo.



1. Padrão Composite

O padrão Composite permite que clientes trabalhem uniformemente com objetos individuais e seus grupos. Esta é uma solução ideal para construir estruturas hierárquicas, como sistemas de arquivos, menus de interface ou cenas gráficas.

Em Kotlin, frequentemente usamos classes sealed para representar nós de árvore. Considere um exemplo de construção de uma estrutura "Arquivos e Pastas":

sealed class FileSystemNode(open val name: String) {    data class File(override val name: String, val size: Long) : FileSystemNode(name)    data class Directory(        override val name: String,        val children: MutableList<FileSystemNode> = mutableListOf()    ) : FileSystemNode(name) {        fun add(node: FileSystemNode) {            children.add(node)        }        fun remove(node: FileSystemNode) {            children.remove(node)        }        fun getTotalSize(): Long = children.sumOf {            when (it) {                is File -> it.size                is Directory -> it.getTotalSize()            }        }    }}

// Usofun main() { val root = FileSystemNode.Directory("root") root.add(FileSystemNode.File("readme.txt", 1024)) val subDir = FileSystemNode.Directory("src") subDir.add(FileSystemNode.File("main.kt", 4096)) root.add(subDir) println("Tamanho total: ${root.getTotalSize()} bytes") // 5120}

Prós: simplifica o código do cliente, suporta operações recursivas. Contras: pode complicar o sistema se a árvore for muito profunda.



2. Padrão Visitor

O padrão Visitor permite adicionar novas operações a objetos sem alterar suas classes. Isso é especialmente útil quando você tem uma hierarquia de classes estável, mas algoritmos de processamento que mudam frequentemente.

Em Kotlin, funciona bem com classes sealed. Vamos implementar um exemplo de cálculo de área para formas geométricas:

sealed class Shapeclass Circle(val radius: Double) : Shape()class Rectangle(val width: Double, val height: Double) : Shape()

interface ShapeVisitor<T> { fun visit(circle: Circle): T fun visit(rectangle: Rectangle): T}

class AreaCalculator : ShapeVisitor<Double> { override fun visit(circle: Circle) = Math.PI * circle.radius * circle.radius override fun visit(rectangle: Rectangle) = rectangle.width * rectangle.height}

// Usofun <T> Shape.accept(visitor: ShapeVisitor<T>): T = when (this) { is Circle -> visitor.visit(this) is Rectangle -> visitor.visit(this)}

fun main() { val shapes = listOf(Circle(5.0), Rectangle(3.0, 4.0)) val calculator = AreaCalculator() shapes.forEach { println("Área: ${it.accept(calculator)}") }}

Quando aplicar: se a estrutura do objeto raramente muda, mas as operações sobre eles mudam com frequência. Em Kotlin, você pode usar when para casos simples, mas o Visitor permanece indispensável para lógica complexa com muitos tipos.



3. Padrão State

O padrão State permite que um objeto mude seu comportamento dependendo de seu estado interno. Esta é uma alternativa elegante para declarações if-else ou switch-case complicadas.

Em Kotlin, podemos usar classes sealed para representar estados. Exemplo — um pedido em uma loja online

Blogs

Book Recommendations