Boas práticas e padrões · Princípios gerais · 5 min de leitura
Composição em vez de herança
Monte comportamento juntando objetos pequenos em vez de empilhar subclasses — mais flexível e menos frágil.
Arraste para o lado para ver o diagrama inteiro.
Por quê
O livro do GoF (1994) já recomendava: "favoreça a composição de objetos à herança de classes". Herança acopla a subclasse aos detalhes internos da classe base (o "problema da classe base frágil") e explode em combinações: MagoVoador, GuerreiroVoador, MagoNadador…
Quando herdar faz sentido
Quando existe uma relação "é-um" estável e o subtipo respeita o contrato (veja Liskov) — por exemplo, telas que estendem uma classe do framework. Kotlin torna classes final por padrão justamente para que a herança seja uma decisão explícita, e oferece delegação (by) como alternativa de primeira classe.
No código
fun interface Movimento { fun mover(): String }
fun interface Ataque { fun atacar(): String }
class Personagem(var movimento: Movimento, var ataque: Ataque) {
fun turno() = "${movimento.mover()} e ${ataque.atacar()}"
}
val andar = Movimento { "anda" }
val voar = Movimento { "voa" }
val magia = Ataque { "lança magia" }
val mago = Personagem(andar, magia)
mago.movimento = voar // pegou a poção: agora voa, sem nova subclasse Duas interfaces pequenas substituem uma árvore de subclasses; combinações novas não exigem tipo novo.
Em resumo
- "Tem-um" é mais flexível que "é-um".
- Evita explosão de subclasses combinadas.
- Permite trocar comportamento em tempo de execução.
- Kotlin: classes final por padrão e delegação com by.