Composição é quando uma classe oferece alguma funcionalidade instanciando uma classe (possivelmente interna) que já implementa essa funcionalidade, em vez de herdar dessa classe.
Portanto, por exemplo, se você tem uma classe que modela um navio, e agora lhe dizem que seu navio deve oferecer um heliponto, não é natural derivar seu navio de um heliponto (duh!), Você deve ter seu navio contém uma classe de heliponto e a expõe por algum Ship.getHelipad()
método.
Nos anos anteriores (há uma década ou mais), as pessoas costumavam ver a herança como uma maneira rápida e fácil de agregar funcionalidades; portanto, havia muitos exemplos do tipo "nave que herdou do heliporto", que eram, obviamente, muito ruins.
Mas o ditado "Favorecer a composição sobre a herança" foi cuidadosamente formulado para deixar claro que isso é apenas uma sugestão, não uma regra. O autor do ditado teve o cuidado de não dizer algo como " nunca usarás herança, apenas composição". Isso está basicamente chamando a atenção da comunidade de engenharia de software para o fato de a herança ter sido usada em excesso, enquanto em muitos casos a composição produz projetos mais claros, elegantes e sustentáveis do que a herança.
Portanto, essencialmente, o ditado "Favorecer a composição sobre a herança" sugere que sempre que você se deparar com o "herdar ou compor?" pergunta, você deve pensar bem qual é a estratégia mais adequada e que há mais chances de que a estratégia mais adequada acabe sendo composição, não herança.
Mas como essa não é uma regra, você também deve ter em mente que há muitos casos em que a herança é mais natural. Se você usar composição lá onde deveria ter usado herança, muitos males ocorrerão no seu código.
Voltando ao exemplo da nave, se sua nave precisar oferecer uma interface para interagir com a FloatingMachine
, é mais natural derivá-la de uma FloatingMachine
classe abstrata , que por sua vez pode ser derivada de outra Machine
classe abstrata .
Aqui está a regra de ouro para a resposta à pergunta composição versus herança:
Minha classe tem um relacionamento "é um" com a interface que precisa expor? Se sim, use herança. Caso contrário, use a composição.
Um navio "é uma" máquina flutuante e uma máquina flutuante "é uma" máquina. Então, herança é perfeitamente adequada para eles. Mas um navio não é, obviamente, um heliporto. Portanto, é melhor compor a funcionalidade do heliponto.