Introdução ao Polimorfismo
Gabriel_Silvestre
Posted on May 19, 2022
Tabela de Conteúdo
- Polimorfismo
- Sobrescrita de Métodos
- Classes Abstratas
- Métodos Estáticos
- Polimorfismo em Interfaces
- Links Úteis
Polimorfismo
O que é?
Na programação, o Polimorfismo remete a capacidade de alterar o comportamento de determinado método de uma Super Classe em qualquer uma das Sub Classes que à herdem.
O que faz?
Como dito em sua definição, permite a alteração de comportamentos de um determinado método sem alterar sua assinatura, dessa forma podemos ter o mesmo método com diferentes comportamentos a depender da classe que o implementa.
Um exemplo disso seria os métodos de ciclo de vida no React, ao trabalharmos o React com classes definimos os métodos de ciclo de vida com diferentes comportamentos dependendo do componente, porém esses métodos continuam a ter o mesmo nome, parâmetros e tipo de retorno.
Tipos
Existem diferentes tipos de Polimorfismo dentro da POO (Programação Orientada a Objetos), porém nesse artigo iremos abordar apenas a Sobrescrita de Métodos com TypeScript.
Sobrescrita de Métodos
O que é?
É a alteração do comportamento padrão de um método da Super Classe para um comportamento mais específico de uma Sub Classe, sendo que, se não o sobrescrevermos o método manterá o comportamento definido na Super Classe.
Sintaxe
Para sobrescrevermos um determinado método, tudo que precisamos fazer é instanciá-lo na Sub Classe e definirmos uma nova lógica.
Uma obervação, os parâmetros e o tipo de retorno do método a ser sobrescrito podem ser mantidos, no intuito de padronizar o método, sendo a única alteração, a lógica interna.
class Person {
constructor(public name: string) {}
move(): void {
console.log(`${this.name} se move`);
}
}
class Runner extends Person {
move() {
console.log(`${this.name} corre`);
}
}
class Lazy extends Person {
move() {
console.log(`${this.name} anda devagar`);
}
}
const john = new Person('John');
const runnerJohn = new Runner('John');
const lazyJohn = new Lazy('John');
john.move(); // John se move
runnerJohn.move(); // John corre
lazyJohn.move(); // John anda devagar
Classes Abstratas
O que são?
São classes que atuam de forma similar a Interfaces, isso porque elas não podem ser instanciadas, apenas herdadas, possibilitando ainda a criação de métodos abstratos, esses que por sua vez só podem existir em Classes Abstratas e devem ser implementados em qualquer Sub Classe de uma Super Classe Abstrata.
A diferença de Classes Abstratas e Interfaces, é que nas classes podemos definir outros métodos e atributos que não são abstratos, ou seja, podem receber funcionalidade e valores.
Sintaxe
Para definirmos Classes/Métodos Abstratos utilizamos a palavra reservada abstract
antes de suas definições.
Lembrando que tudo que for abstrato, não pode ser implementado, apenas definido, e nada nos impede de criarmos métodos comuns dentro de Classes Abstratas.
abstract class Person {
constructor(public name: string) {}
/*
mesmo estando em uma classe abstrata, ainda podemos criar métodos comuns
que não precisam ser obrigatoriamente implementados nas Sub Classes.
*/
greetings() {
console.log(`Eu me chamo ${this.name}`);
}
abstract move(): void;
}
class Runner extends Person {
move() { // o método abstrato precisa ser implementado nas Sub Classes
console.log(`${this.name} corre`);
}
}
class Lazy extends Person {
move() {
console.log(`${this.name} anda devagar`);
}
}
const runnerJohn = new Runner('John');
const lazyJohn = new Lazy('John');
runnerJohn.move(); // John corre
runnerJohn.greetings(); // Eu me chamo John
lazyJohn.move(); // John anda devagar
lazyJohn.greetings(); // Eu me chamo John
Métodos Estáticos
O que são?
São métodos que não interagem com as instancias da classe, ou seja, manipulam as informações ligadas a classe em si, não a instância.
Também existem os atributos estáticos que assim como os métodos estão vinculados a classe e não as instâncias.
Sintaxe
Para definirmos Métodos/Atributos Estáticos utilizamos a palavra reservada static
antes de suas definições.
class GroupMember {
private static groupSize = 0;
constructor(public newPerson: string) {
Group.addMember();
}
private static addMember() {
this.groupSize += 1;
}
static get size() {
return this.groupSize;
}
}
console.log(GroupMember.size); // 0
const member1 = new GroupMember('John');
console.log(GroupMember.size); // 1
const member2 = new GroupMember('John');
console.log(GroupMember.size); // 2
Polimorfismo em Interfaces
O que é?
Assim como nas classes, as Interfaces também podem ser polimorfas, ou seja, ter diferentes comportamentos a depender da implementação. Esse é o comportamento padrão de toda a Interface, afinal só definimos a assinatura, parâmetros e retorno do método, enquanto a lógica interna fica por nossa conta.
Porém podemos ainda utilizar das Generics criar classes e até funções ainda mais dinâmicas, dessa forma o tipo será determinado no momento de sua criação e não na definição.
Sintaxe
Como dito acima, o comportamento padrão de métodos definidos na Interface é serem polimórficos, logo sua definição continua a mesma.
Já para utilizarmos Generics, tudo que precisamos fazer é nós utilizar dos símbolos de maior e menor <>
, colocando entre eles uma letra por convenção em maiúsculo.
interface IGame<T> {
title: string;
platform: string;
controls: T;
}
type FPSControls = {
W: 'up',
A: 'left',
S: 'down',
D: 'right',
}
class FPSGame extends IGame<FPSControls> {
constructor(
public title: string,
public platform: string,
public controls: FPSControls
) {}
}
type MOBAControls = {
Q: 'firstAbility',
W: 'secondAbility',
E: 'thirdAbility',
R: 'ultimate',
}
class MOBAGame extends IGame<MOBAControls> {
constructor(
public title: string,
public platform: string,
public controls: MOBAControls
) {}
}
Links Úteis
Posted on May 19, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.