Os 4 pilares da Programação Orientada a Objeto
Entenda tudo dos 4 pilares da programação orientada a objeto (POO) — Encapsulamento, Herança, Polimorfismo e Abstração.
Diagrama de classe — UML
Em programação, um diagrama de classes é uma representação da estrutura e relações das classes que servem de modelo para objetos. Podemos afirmar de maneira mais simples que seria um conjunto de objetos com as mesmas características, assim saberemos identificar objetos e agrupá-los, para encontrar suas respectivas classes. Na Unified Modeling Language (UML) em diagrama de classe, uma classe é representada por um retângulo com três divisões, são elas: O nome da classe, seus atributos e por fim os métodos.
Encapsulamento
Encapsulamento se refere à construção do objeto de modo a proteger o acesso direto a seus dados internos. Ao encapsular um objeto estamos agrupando propriedades e métodos diretamente relacionados em um mesmo objeto, permitindo que essas propriedades sejam acessadas somente por métodos públicos. Desta forma tratamos de questões importantes como segurança e confiabilidade do estado do objeto.
Encapsulamento, na prática — C# e Java
Para exemplificar irei criar uma classe chamada Pessoa, com os atributos, nome, idade e e-mail, mas não haverá métodos.
Apesar das diferenças, ambos códigos fazem o mesmo, permitem que classes externas possam recuperar valores atribuídos a classe Pessoa. O encapsulamento é bastante usado quando o desenvolvedor deseja não permitir que o usuário altere algo crítico das informações, mas em compensação tenha a possibilidade de visualizá-la, como o CPF em uma plataforma web ou mobile. O Getter permite visualizar (pegar) e o Setter modificar.
Herança
A Herança possibilita que as classes compartilhem seus atributos, métodos e outros membros da classe entre si. Para a ligação entre as classes, a herança adota um relacionamento esquematizado hierarquicamente.
Na Herança temos dois tipos principais de classe:
- Classe Base: A classe que concede as características a outra classe.
- Classe Derivada: A classe que herda as características da classe base.
Note que ambas as classes à esquerda, possuem atributos em comum, como number, holder, balance, ao invés de criarmos duas classes e repetir os atributos em ambas, utilizamos uma classe mais genérica, denominada de superclasse, e fazemos a subclasse herdar os seus atributos e métodos (exemplo à direita).
Para uma classe conseguir herdar de outra é indispensável a criação de um construtor vazio na superclasse.
Não é necessário recriar o construtor completamente na subclasse, para ser mais prático podemos usar base (na linguagem C#) e super (na linguagem Java).
Para a imagem não ocupar muito espaço, não coloquei o encapsulamento, mas é de extrema importância criar os getter e setter dos atributos. Em java para uma subclasse herdar da superclasse usa-se o termo extends.
Em C# para uma subclasse herdar da superclasse usa-se o simbolo : (dois pontos).
Para resumir, herança nos faz reutilizar código e deixar o ambiente de desenvolvimento mais moderno e limpo.
Quando herdamos de uma superclasse, não só é herdado os atributos, mas também os métodos.
Polimorfismo
O polimorfismo é também conhecido como sobrecarga de métodos, ocorre quando duas ou mais funções, ou métodos têm o mesmo nome, mas diferem em seus parâmetros, gerando valores diferentes e respeitando a regra de negócio.
Get Pedro Aquino’s stories in your inbox
Join Medium for free to get updates from this writer.
Essa característica é essencial para a flexibilidade e a reutilização de código, por permitir que métodos e funções operem em diferentes tipos de dados sem a necessidade de saber exatamente qual tipo de dado está sendo manipulado. No contexto da programação o polimorfismo pode ser dividido e, duas categorias principais: polimorfismo em tempo de compilação e polimorfismo em tempo de execução.
Enunciado
Uma empresa possui funcionários próprios e terceirizados. Para cada funcionário, deseja-se registrar nome, horas trabalhadas e valor por hora. Funcionários terceirizados possuem ainda uma despesa adicional. O pagamento dos funcionários corresponde ao valor da hora multiplicado pelas horas trabalhadas, sendo que os funcionários terceirizados ainda recebem um bônus correspondente a 110% de sua despesa adicional.
Observe que, no diagrama, ambas as classes possuem o método payment(). No entanto, conforme descrito no enunciado, esse cálculo será realizado de maneira diferente em cada classe.
- Na classe Employee, o valor do pagamento é obtido somente pela multiplicação dos atributos valuePerHour e hours.
- Já na classe OutsourcedEmployee, o cálculo deve incluir uma despesa adicional. Por isso, além da multiplicação básica, adicionam-se 110% do valor da despesa ao total, conforme regra definida.
Para o polimorfismo ocorrer corretamente em C#, o método da superclasse precisa ser declarado com o modificador virtual. Isso indica que ele pode ser sobrescrito pelas subclasses.
Na subclasse, utilizamos a notação override para indicar que estamos redefinindo o comportamento do método herdado. Além disso, a palavra-chave base pode ser usada para acessar a implementação original do método na superclasse.
No caso do método Payment(), como a lógica base de cálculo (multiplicação de ValuePerHour por Hours) é a mesma, reutilizamos essa parte por meio de base.Payment() na subclasse OutsourcedEmployee. Em seguida, adicionamos os 110% sobre a despesa adicional, conforme exigido.
Para o polimorfismo funcionar corretamente em Java, o método da superclasse deve ser definido de forma que possa ser sobrescrito — ou seja, sem estar marcado como final ou private.
Na subclasse, utilizamos a anotação @Override para indicar que estamos reescrevendo o comportamento do método herdado. Isso ajuda a garantir que o método da superclasse está realmente sendo substituído e evita erros de digitação.
Abstração
A abstração na POO é a capacidade de ocultar detalhes irrelevantes ou complexos de um problema e focar nos aspectos essenciais. Ela é implementada por meio de classes, sendo modelos que descrevem os atributos e comportamentos comuns de um grupo de objetos.
Em Java as classes abstratas não podem ser instanciadas diretamente. Elas só podem ser implementadas por outras classes. Você pode pensar da seguinte maneira, uma classe abstrata te diz o que fazer, mas não te diz como fazer. E com isso espero que diferencie o pilar da abstração das classes abstratas no Java.
A classe TaxPayer é abstrata, assim como o método tax(), na representação UML classes e métodos abstratos são referenciados por meio da fonte itálico, significa que não podemos instanciar estas classes.
Podemos realizar um upcasting, que consiste em tratar um objeto da subclasse como se fosse da superclasse. Isso é perfeitamente válido em Java e C# é muito utilizado para aplicar o polimorfismo em tempo de execução.
Benefícios das Classes Abstratas
- Modelagem de conceitos genéricos Permite representar uma entidade base comum (ex: Funcionario, Animal, Forma), que serve de modelo para outras classes mais específicas.
- Reutilização de código Pode conter atributos e métodos concretos que serão herdados pelas subclasses, evitando repetição de código.
- Obrigatoriedade de implementação Métodos abstratos obrigam as subclasses a fornecerem suas próprias implementações, garantindo um contrato de comportamento.
- Organização e manutenção do código Favorece uma estrutura hierárquica clara e consistente no projeto, facilitando a leitura e manutenção.
- Suporte ao polimorfismo Permite utilizar o polimorfismo eficientemente, tratando diferentes objetos por meio de uma referência comum abstrata.
Autor: Pedro Aquino — Desenvolvedor Back-End
Referências







