Como Organizar Seu Código Orientado a Objetos com Herança
É comum reutilizar código na programação orientada a objetos. As classes existem para que você possa criar objetos sem ter que escrever as mesmas variáveis e funções repetidamente.
Mas e as aulas em si? Às vezes, as classes também são muito semelhantes. Por exemplo, uma árvore tem galhos, raízes e um tronco. Isso se aplica a Elms, Oaks e Ponderosa Pines.
Se você estivesse adicionando uma árvore a um jogo, poderia criar partes de árvores para dezenas de árvores. Mas seria mais fácil criar uma classe de árvore e fazer com que todas as outras árvores herdassem suas propriedades.
Por que a herança é importante?
Existe um conceito na programação orientada a objetos chamado "mantê-lo DRY". DRY significa "Don't Repeat Yourself". Se você se pega copiando e colando muitos códigos, também está introduzindo espaço para muitos erros.
Digamos que você esteja escrevendo o código de um novo jogo Tamagotchi. O primeiro animal de estimação virtual será um urso polar. Portanto, você cria uma classe chamada PolarBear em JavaScript / TypeScript.
class PolarBear {
private _weight: number = 990;
constructor(weight: number = 0) {
this._weight = weight
}
makeNoise() {
console.log("made a roar");
}
eat() {
console.log("eats whatever it wants");
}
sleep() {
console.log("got a good night's sleep");
}
roam() {
console.log("wandered about aimlessly");
}
}
Então seu chefe lhe diz que a alta administração teve um grande avanço. Eles perceberam que não é mais os anos 90 e eles podem acomodar mais de 5K de memória no Tamagotchi. E agora eles querem todos os ursos.
Você arregaça as mangas e volta ao trabalho, criando cópias da aula de urso. Então seu chefe bate na sua porta novamente. Acontece que eles querem que o jogo seja mais educacional. Agora você deve adicionar informações de origem a cada animal.
Você não está mais duplicando o código. Agora você está alterando centenas de linhas de código para todas as oito espécies de urso. É assim que os erros acontecem e os bugs são introduzidos.
Enquanto você está se arrastando, seu chefe se aproxima de novo. Agora, a alta gerência quer todos os roedores no jogo também. Ah, e uma girafa.
Você sabe que, quando terminar, eles vão querer macacos ou alguma outra coisa também. Deve haver uma maneira melhor.
Em vez de criar Tamogatchi da próxima geração, você sempre pode brincar com os existentes .
Herança para o resgate
Para domesticar seu zoológico virtual, você precisa se organizar. A herança ajuda a organizar suas classes, adicionando relações de pai e filho a elas.
Ursos negros, pardos e ursos-preguiça são todos ursos. Ursos, roedores e macacos são todos animais. E é assim que estruturaremos nossa árvore genealógica.
Esta é a aparência de uma parte do código:
class Animal {
private _weight: number;
private _origin: string;
constructor(weight: number = 0, origin: string = "") {
this._weight = weight;
this._origin = origin;
}
makeNoise(noise: string = "") {
console.log("made a noise that sounded like: " + noise);
}
eat(food: string = "") {
console.log("eats " + food);
}
sleep() {
console.log("got a good night's sleep");
}
roam() {
console.log("wandered about aimlessly");
}
}
class Bear extends Animal {
constructor(weight: number, origin: string) {
super(weight, origin);
}
makeNoise(noise: string = "roar") {
super.makeNoise(noise);
}
eat(food: string = "whatever it wants") {
super.eat(food);
}
}
class GrizzlyBear extends Bear {
constructor(weight: number = 600, origin: string = "North America") {
super(weight, origin);
}
}
class Panda extends Bear {
constructor(weight: number = 230, origin: string = "China") {
super(weight, origin);
}
makeNoise() {
super.makeNoise("squeek");
}
eat() {
super.eat("shoots and leaves");
}
}
Você pode brincar com o código na caixa de proteção TypeScript .
Esse foi um grande exemplo, mas o código é bastante simples e todas as classes descendem da classe Animal . Você pode ver que Bear estende Animal . E GrizzlyBear e Panda estendem a classe Bear . A classe Bear cria funções padrão de som e alimentação . A classe GrizzlyBear usa essas funções padrão, mas o Panda não.
Em outras palavras, a classe GrizzlyBear não substitui as funções do Bear . Como o GrizzlyBear estende o Bear , ele usará as funções definidas pelo Bear automaticamente. Mas, como o Panda substitui as funções makeNoise e eat , ele as usará.
Encontrando relacionamentos com a técnica "é um, tem um"
Para descobrir se uma classe realmente deve estender outra classe, você pode se perguntar se há uma relação "é um" ou "tem um" entre eles.
- Um lêmure "é" um macaco.
- Um canguru "é" um marsupial.
- No entanto, o pé de um coelho não é um coelho. Um coelho "tem" um pé.
Este exemplo é um pouco simplista, mas ao lidar com classes do mundo real, pode ser muito útil.
Prática e compreensão de herança prática
Pronto para aplicar o que aprendeu?
- Visite a caixa de areia e preencha o restante das classes de animais do exemplo acima.
- Adicione uma classe Monkey .
- Adicione uma classe ProboscisMonkey que estenda sua classe de macaco.
A herança é mais do que apenas um código bem organizado. É uma parte central da programação orientada a objetos. A herança ajuda a otimizar a comunicação entre objetos. E permite um design orientado a objetos mais avançado, como com polimorfismo. Você pode aprender mais sobre herança na documentação do TypeScript .