A programação orientada a objetos, frequentemente chamada de POO, é um paradigma de desenvolvimento que organiza o software em torno de objetos que representam elementos do mundo real ou conceitos abstratos. Esses objetos combinam dados e comportamentos, criando estruturas mais robustas, modulares e reutilizáveis. Esse paradigma mudou profundamente a forma de projetar sistemas por permitir um maior nível de organização e por aproximar a estrutura do código das situações reais que ele tenta resolver.
Pra que serve ?
A programação orientada a objetos serve principalmente para tornar o software mais modular, flexível e fácil de manter. Ela permite que partes do programa sejam construídas de forma independente e depois integradas, garantindo maior organização estrutural. Também facilita o trabalho colaborativo, já que diferentes desenvolvedores podem atuar sobre classes distintas sem comprometer o restante da aplicação. Além disso, torna o código mais extensível, pois novos recursos podem ser adicionados sem exigir alterações profundas no que já existe. Essa característica é fundamental em projetos de grande porte, nos quais o controle da complexidade e da evolução do sistema é indispensável.
Vantagens
- Promove a reutilização de código por meio de herança e composição.
- Facilita a manutenção por permitir que alterações fiquem restritas a partes específicas do sistema.
- Aumenta a organização ao separar responsabilidades dentro de classes distintas.
- Melhora a legibilidade ao criar estruturas que seguem um modelo lógico próximo da realidade do domínio.
- Incentiva a criação de testes mais simples devido ao isolamento de funcionalidades em objetos independentes
Desvantagens
- Aumenta a complexidade inicial devido à necessidade de modelar classes, objetos e relacionamentos.
- Pode se tornar excessivamente abstrata quando muitos níveis de herança são usados sem necessidade real.
- Pode gerar código mais verboso em algumas linguagens quando comparada a paradigmas como programação funcional.
- Incentiva arquiteturas demasiadamente acopladas quando princípios de boas práticas não são seguidos.
Pilares do paradigma orientado a objetos
Os pilares fundamentais da programação orientada a objetos dão suporte ao paradigma e definem as regras estruturais que tornam o modelo eficiente. Mas antes de entender esses pilares, você precisa dominar o conceito de classe e objeto.

Encapsulamento
O encapsulamento garante proteção aos dados internos da classe. Ele impede que atributos sejam acessados diretamente de fora, exigindo que a interação aconteça por meio de métodos específicos.
Exemplo de encapsulamento
Imagine uma classe Pessoa com um atributo privado chamado nome. Para modificar e acessar esse atributo, são utilizados métodos públicos como setNome e getNome. A vantagem disso é permitir validação, segurança e controle sobre os dados internos, evitando inconsistências e manipulações indevidas.
class Pessoa {
private String nome;
public void setNome(String nome) {
this.nome = nome;
}
public String getNome() {
return nome;
}
}
class main(String args[]){
Pessoa pessoa = new Pessoa();
pessoa.setNome("João");
printf("O nome da pessoa é" + pessoa.getNome());
}
Abstração
A abstração é outro pilar essencial e consiste em ocultar detalhes internos, expondo apenas o necessário para uso externo. Ela permite representar conceitos complexos de forma clara, definindo apenas a interface que um objeto deve oferecer.
Exemplo de abstração
Um exemplo comum em Java é criar uma classe abstrata chamada Forma que define o método calcularArea sem fornecer implementação. Classes concretas, como Circulo, herdam de Forma e implementam o cálculo de área conforme suas características específicas. Assim, o código pode manipular objetos do tipo Forma sem conhecer a lógica interna de cada figura geométrica. Abaixo podemos analisar s implementação dessse exemplo.
abstract class Forma {
abstract double calcularArea();
}
class Circulo extends Forma {
double raio;
Circulo(double raio) {
this.raio = raio;
}
double calcularArea() {
return Math.PI * raio * raio;
}
}
Herança
A herança, que possibilita a criação de novas classes baseadas em classes já existentes. Esse mecanismo permite que subclasses herdem atributos e métodos das classes superiores, favorecendo a reutilização e a especialização de comportamentos. Aprenda mais sobre o conceito de herança clicando aqui.
Exemplo de herança
class Animal {
void emitirSom() {
System.out.println("Som genérico");
}
}
class Gato extends Animal {
void emitirSom() {
System.out.println("Miado");
}
}
class Cachorro extends Animal {
void emitirSom() {
System.out.println("Latido");
}
}
A classe Animal possui o método emitirSom, que imprime um som genérico. A classe Cachorro e Gato estende Animal e sobrescreve o método emitirSom para imprimir um som específico. Isso mostra como a herança permite reaproveitar e especializar comportamentos, pois atráves de uma classe que é herdada pelas outras é possível usar um método que já foi definido.
Polimorfismo
O polimorfismo, permite que um mesmo método execute comportamentos diferentes conforme o objeto que o utiliza. Isso ocorre porque subclasses podem sobrescrever métodos herdados da classe base.
Exemplo de polimorfismo
Considere uma classe Forma com o método calcularArea retornando zero. A classe Quadrado, ao herdar Forma, sobrescreve o método para calcular o valor multiplicando lado por lado. Já a classe Circulo implementa o mesmo método com a fórmula baseada no raio. Se um objeto de cada classe for armazenado em variáveis do tipo Forma, cada um responderá ao método calcularArea de maneira distinta. Isso confere flexibilidade ao sistema, pois permite a substituição de objetos sem alterar o código que os utiliza.
class Forma {
double calcularArea() {
return 0;
}
}
class Quadrado extends Forma {
double lado;
Quadrado(double lado) {
this.lado = lado;
}
double calcularArea() {
return lado * lado;
}
}
class Circulo extends Forma {
double raio;
Circulo(double raio) {
this.raio = raio;
}
double calcularArea() {
return Math.PI * raio * raio;
}
}
Desafio
A partir desse post vimos os quatro pilares que regem a programação orientada a objetos. Agora é sua vez de aplicar esses conceitos.
Uma empresa de tecnologia deseja desenvolver um sistema para gerenciar seus funcionários. O sistema deve ser capaz de representar diferentes tipos de funcionários, armazenar seus dados e calcular corretamente o salário final de cada um de acordo com regras específicas.
Todo funcionário da empresa possui nome, matrícula e salário base. A partir desse conceito geral, existem três categorias distintas de funcionários: Desenvolvedor, Gerente e Estagiário. Cada categoria possui uma forma diferente de cálculo do salário final. O Desenvolvedor recebe um bônus de 20% sobre o salário base, o Gerente recebe um bônus de 40% sobre o salário base e o Estagiário não recebe nenhum tipo de bônus, recebendo apenas o valor do salário base.
O sistema deve ser estruturado de forma que exista uma entidade genérica representando o conceito de Funcionário, a partir da qual as demais categorias serão derivadas. Essa entidade deve concentrar os atributos e comportamentos comuns a todos os funcionários. As classes específicas de Desenvolvedor, Gerente e Estagiário devem herdar dessa entidade genérica e especializar o comportamento relacionado ao cálculo do salário final.
Os atributos dos funcionários não devem ser acessados diretamente, sendo necessário o uso de mecanismos de proteção para garantir o encapsulamento e a integridade dos dados. O cálculo do salário final deve ser realizado por meio de um método comum, porém com comportamentos diferentes dependendo do tipo de funcionário, de forma que o polimorfismo seja aplicado.
Ficou curioso para saber como resolver esse problema ? Acompanhe a solução no canal do YouTube.
