Sobes.tech
Middle

Em que situações a herança na programação orientada a objetos é útil e em que casos deve ser evitada?

sobes.tech IA

Resposta da IA

A herança é útil para:

  • Reutilização de código: A funcionalidade comum é colocada numa classe base.
  • Criação de hierarquias de tipos (relação is-a): Quando uma classe filha é uma variação da classe pai.
  • Polimorfismo: A capacidade de tratar objetos de diferentes tipos através de uma interface comum da classe base.
  • Extensão de funcionalidades: Adicionar novos métodos ou campos a uma classe existente.

Deve evitar-se a herança quando:

  • O princípio de substituição de Liskov é violado: A classe filha não pode substituir completamente a classe base sem alterar a correção do programa.
  • Cria-se uma ligação rígida entre classes: As alterações na classe base podem afetar indesejadamente todas as classes filhas.
  • É necessário combinar funcionalidades de fontes não relacionadas (relação has-a): É melhor usar composição.
  • Complexidade excessiva na hierarquia: Cadeias profundas de herança são difíceis de manter e compreender.
  • Herança para reutilização de código quando a funcionalidade não é um "tipo" comum: É melhor usar classes utilitárias ou delegação.
// Exemplo, quando a herança é útil
open class Animal {
    open fun makeSound() {
        println("Som genérico de animal")
    }
}

class Dog : Animal() { // Dog É-UMA Animal
    override fun makeSound() {
        println("Au au")
    }
}

class Cat : Animal() { // Cat É-UMA Animal
    override fun makeSound() {
        println("Miau")
    }
}
// Exemplo, quando a composição é preferível à herança para a relação "has-a"
class Engine {
    fun start() { println("Motor iniciado") }
}

// Em vez de herdar de Engine para Car
// class Car : Engine() // Má conceção, Car NÃO É-UMA Engine

class Car {
    private val engine = Engine() // Car TEM-UMA Engine
    fun drive() {
        engine.start()
        println("Carro a conduzir")
    }
}