Orientação a objetos: herança e polimorfismo
Continuação do post sobre orientação a objetos. Agora vamos ver os dois conceitos que fecham o quarteto: herança e polimorfismo.
No post anterior a gente viu encapsulamento e abstração, os dois primeiros conceitos da orientação a objetos. Se você ainda não leu, vale dar uma passada por lá antes de continuar aqui.
Agora vamos para os dois conceitos que fecham o quarteto: herança e polimorfismo. Eles são um pouco mais avançados, mas seguem a mesma lógica prática dos anteriores.
Herança
O nome já diz bastante. Herança é quando uma classe herda as propriedades e os métodos de outra classe.
Vamos usar o exemplo do funcionário que a gente criou antes. Toda empresa tem tipos diferentes de funcionário. Um programador é um funcionário, um gerente é um funcionário, um vendedor é um funcionário. Todos eles têm nome, salário base, horas extras. Mas cada um também tem coisas específicas da sua função.
Sem herança, você criaria uma classe separada para cada tipo e repetiria as mesmas propriedades em todas elas:
class Programador {
public $nome;
public $salarioBase;
public $horasExtras;
public $linguagem; // específico do programador
}
class Gerente {
public $nome;
public $salarioBase;
public $horasExtras;
public $numeroDeFuncionarios; // específico do gerente
}Voltou o problema do copy e paste. Se amanhã você precisar adicionar uma nova propriedade comum a todos os funcionários, vai ter que adicionar em cada classe separadamente.
Com herança você cria uma classe base com o que é comum, e as outras classes herdam dela:
class Funcionario {
public $nome;
public $salarioBase;
public $horasExtras;
public $valorDaHora;
public function getSalarioEfetivo() {
return $this->salarioBase + ($this->horasExtras * $this->valorDaHora);
}
}
class Programador extends Funcionario {
public $linguagem;
}
class Gerente extends Funcionario {
public $numeroDeFuncionarios;
}O Programador e o Gerente herdam automaticamente tudo que está na classe Funcionario. Você não precisa repetir nada. E se precisar adicionar uma nova propriedade em todos os funcionários, adiciona só na classe base e todos os filhos recebem automaticamente.
Na prática fica assim:
$programador = new Programador();
$programador->nome = "Fulano";
$programador->salarioBase = 5000;
$programador->horasExtras = 8;
$programador->valorDaHora = 50;
$programador->linguagem = "PHP";
echo $programador->getSalarioEfetivo(); // 5400O Programador tem acesso ao método getSalarioEfetivo mesmo sem ter definido ele, porque herdou de Funcionario.
Polimorfismo
Polimorfismo significa "muitas formas". Na prática significa que você pode ter o mesmo método em classes diferentes, e cada classe vai executar esse método do seu próprio jeito.
Continuando o exemplo: o cálculo de salário efetivo pode ser diferente para cada tipo de funcionário. Um gerente recebe uma bonificação extra. Um vendedor recebe comissão. A conta de cada um é diferente, mas todos têm um método chamado getSalarioEfetivo.
class Funcionario {
public $nome;
public $salarioBase;
public $horasExtras;
public $valorDaHora;
public function getSalarioEfetivo() {
return $this->salarioBase + ($this->horasExtras * $this->valorDaHora);
}
}
class Gerente extends Funcionario {
public $bonificacao;
public function getSalarioEfetivo() {
$salarioBase = parent::getSalarioEfetivo();
return $salarioBase + $this->bonificacao;
}
}
class Vendedor extends Funcionario {
public $comissao;
public function getSalarioEfetivo() {
$salarioBase = parent::getSalarioEfetivo();
return $salarioBase + $this->comissao;
}
}O Gerente e o Vendedor sobrescrevem o método getSalarioEfetivo com a lógica específica deles. O parent::getSalarioEfetivo() chama o método da classe pai, que é o cálculo base, e cada classe adiciona o que é específico dela por cima.
A grande sacada do polimorfismo aparece quando você tem uma lista de funcionários de tipos diferentes e precisa calcular o salário de todos:
$funcionarios = [
new Programador(),
new Gerente(),
new Vendedor(),
];
foreach ($funcionarios as $funcionario) {
echo $funcionario->getSalarioEfetivo();
}O código que percorre a lista não precisa saber se está lidando com um programador, um gerente ou um vendedor. Ele simplesmente chama getSalarioEfetivo em cada um e cada objeto responde do seu próprio jeito. Mesma chamada, comportamentos diferentes. Isso é polimorfismo.
Por que isso tudo importa
Esses quatro conceitos, encapsulamento, abstração, herança e polimorfismo, existem para resolver o mesmo problema: organizar o código de um sistema grande de forma que ele seja fácil de manter e de expandir.
Sem eles, quando o sistema cresce, o código vira uma bagunça difícil de mexer. Com eles, você consegue adicionar novos tipos de funcionário sem tocar nas partes que já existem, mudar a regra de cálculo de salário em um lugar só, e garantir que o sistema inteiro se comporta de forma consistente.
A orientação a objetos não é receita de bolo para qualquer situação. Mas quando o sistema tem muitas entidades, muitas regras de negócio e muitos lugares reutilizando as mesmas lógicas, ela é a forma mais organizada de estruturar tudo isso.
Leia também