1. Pégaso

Vamos dar uma olhada mais profunda no terceiro princípio da POO : herança . Este é um tópico muito interessante que você usará com frequência. Para os não iniciados, a programação é indistinguível da magia. Então vamos começar com uma analogia interessante...;

Digamos que você seja um mago que deseja criar um cavalo voador. Por um lado, você pode tentar conjurar um pégaso. Mas como os pégasos não existem na natureza, isso será muito difícil. Você terá que fazer muito sozinho. É muito mais fácil pegar um cavalo e conjurar suas asas.

Na programação, esse processo é chamado de "herança". Suponha que você precise escrever uma classe muito complexa. Demora muito para escrever o código do zero e depois testar tudo por muito tempo para procurar erros. Por que seguir o caminho mais difícil? É melhor verificar se essa classe já existe.

Suponha que você encontre uma classe cujos métodos implementem 80% da funcionalidade de que você precisa. O que você faz com isso a seguir? Você poderia simplesmente copiar seu código em sua classe. Mas esta solução tem várias desvantagens:

  1. A classe que você encontra pode já estar compilada em bytecode e você pode não ter acesso ao seu código-fonte.
  2. O código-fonte da classe está disponível, mas você trabalha para uma empresa que pode ser processada em alguns bilhões por usar até 6 linhas do código de outra pessoa. E então seu empregador irá processá-lo.
  3. Duplicação desnecessária de uma grande quantidade de código. Além disso, se o autor de uma classe externa encontrar um bug nela e corrigi-lo, você ainda terá o bug.

Existe uma solução mais elegante e não requer acesso legal ao código da classe original. Em Java, você pode simplesmente declarar essa classe como pai de sua classe. Isso será equivalente a adicionar o código dessa classe ao seu próprio código. Sua classe verá todos os dados e todos os métodos da classe pai. Por exemplo, você pode fazer isso: herdamos "cavalo" e adicionamos "asas" para obter um "pegaso"


2. Classe base comum

A herança também pode ser usada para outros fins. Digamos que você tenha dez classes muito semelhantes. Eles têm os mesmos dados e métodos. Você pode criar uma classe base especial, mover os dados (e métodos associados) para essa classe base e declarar essas dez classes como descendentes. Em outras palavras, em cada classe indique que sua classe pai é esta classe base.

Assim como as vantagens da abstração são reveladas apenas ao longo do encapsulamento lateral, também as vantagens da herança são muito aprimoradas ao usar o polimorfismo. Mas você aprenderá sobre isso um pouco mais tarde. Hoje veremos vários exemplos de uso de herança.

Peças de xadrez

Suponha que estamos escrevendo um programa que joga xadrez com um usuário humano. Assim, precisamos de classes para representar as peças. Que aulas seriam?

Se você já jogou xadrez, a resposta óbvia é Rei, Rainha, Bispo, Cavalo, Torre e Peão.

Mas as próprias classes ainda precisariam armazenar informações sobre cada peça. Por exemplo, as coordenadas x e y e o valor da peça. Afinal, algumas peças são mais valiosas que outras.

Além disso, as peças se movem de maneira diferente, o que significa que as classes implementarão comportamentos diferentes. Veja como você pode defini-los como classes:

class King
{
   int x;
   int y;
   int worth;

   void kingMove()
   {
     // Code that decides
     // how to move
     // the king
   }
}
class Queen
{
   int x;
   int y;
   int worth;

   void queenMove()
   {
     // Code that decides
     // how to move
     // the queen
   }
}
class Rook
{
   int x;
   int y;
   int worth;

   void rookMove()
   {
     // Code that decides
     // how to move
     // the rook
   }
}
class Knight
{
   int x;
   int y;
   int worth;

   void knightMove()
   {
     // Code that decides
     // how to move
     // the knight
   }
}
class Bishop
{
   int x;
   int y;
   int worth;

   void bishopMove()
   {
     // Code that decides
     // how to move
     // the bishop
   }
}
class Pawn
{
   int x;
   int y;
   int worth;

   void pawnMove()
   {
     // Code that decides
     // how to move
     // the pawn
   }
}

Esta é uma descrição muito primitiva das peças de xadrez.

classe base comum

E aqui está como você pode usar a herança para reduzir a quantidade de código. Podemos trazer os métodos e dados comuns para uma classe comum. Nós vamos chamá-lo ChessItem. Não adianta criar objetos do ChessItem class, já que a classe não corresponde a nenhuma peça de xadrez . Dito isso, a classe será muito útil:

class King extends ChessItem
{
   void kingMove()
   {
     // Code that decides
     // how to move the king
   }
}
class Queen extends ChessItem
{
   void queenMove()
   {
     // Code that decides
     // how to move the queen
   }
}
class Rook extends ChessItem
{
   void rookMove()
   {
     // Code that decides
     // how to move the rook
   }
}
class ChessItem
{
   int x;
   int y;
   int worth;
}
class Knight extends ChessItem
{
   void knightMove()
   {
     // Code that decides
     // how to move the knight
   }
}
class Bishop extends ChessItem
{
   void bishopMove()
   {
     // Code that decides
     // how to move the bishop
   }
}
class Pawn extends ChessItem
{
   void pawnMove()
   {
     // Code that decides
     // how to move the pawn
   }
}

Esta é uma ótima maneira de simplificar o código para objetos semelhantes. Os benefícios são particularmente perceptíveis quando há milhares de objetos diferentes e centenas de classes no projeto. Portanto, as classes pai (base) selecionadas corretamente permitem que você não apenas simplifique bastante a lógica, mas também reduza o código em dez vezes.


3. Herança de classe —extends

Então, o que é necessário para herdar uma classe? Para que uma classe herde outra, você precisa escrever a extendspalavra-chave após a declaração da classe filha e, em seguida, escrever o nome da classe pai. Geralmente é mais ou menos assim:

class Descendant extends Parent

Isso é o que você precisa escrever ao declarar a classe Descendant. A propósito, uma classe pode herdar apenas uma classe.

Na foto, vemos que uma vaca herdou um porco, que herdou uma galinha, que herdou um ovo. Apenas um pai! Essa herança nem sempre é lógica. Mas quando tudo o que você tem é um porco e realmente precisa de uma vaca, os programadores geralmente não resistem ao impulso de transformar um porco em uma vaca.

Java não possui herança múltipla: uma classe não pode herdar duas classes. Cada classe pode ter apenas uma classe pai. Se nenhuma classe pai for especificada, a classe pai será Object.

Dito isso, Java tem herança múltipla de interfaces. Isso atenua um pouco o problema. Falaremos sobre interfaces um pouco mais tarde, mas por enquanto vamos continuar a explorar a herança.