Curso: Orientação a objetos com Java

Tempo de leitura: 8 minutos

1. Introdução à Programação Orientada a Objetos

Objetivo: Entender os conceitos fundamentais de POO e sua importância.

  • Tópicos:
    • O que é POO? Diferença entre programação estruturada e orientada a objetos.
    • Pilares da POO: Encapsulamento, Herança, Polimorfismo e Abstração.
    • Classes e objetos: conceitos e exemplos práticos.

1.1 Conceito de POO e diferença para programação estruturada.

A Programação Orientada a Objetos (POO) é um paradigma de programação que organiza o código em torno de objetos, que são instâncias de classes. Cada objeto representa uma entidade do mundo real (como um carro, uma pessoa ou uma conta bancária) e combina dados (atributos) e comportamentos (métodos) relacionados. A POO é baseada em quatro pilares principais:

  • Encapsulamento: Protege os dados de uma classe, controlando o acesso por meio de modificadores (como private e public) e métodos (getters/setters).
  • Herança: Permite que uma classe herde características de outra, promovendo reutilização de código.
  • Polimorfismo: Permite que objetos de diferentes classes sejam tratados de forma uniforme, utilizando interfaces ou sobrescrita de métodos.
  • Abstração: Simplifica sistemas complexos ao modelar apenas os aspectos relevantes, usando classes abstratas ou interfaces.

A POO é amplamente utilizada em linguagens como Java, pois facilita a criação de sistemas modulares, reutilizáveis e fáceis de manter.

1.2 Pilares da POO: Encapsulamento, Herança, Polimorfismo, Abstração.

A programação estruturada é um paradigma mais antigo, centrado em funções e procedimentos, onde o foco está na sequência lógica de instruções. Ela organiza o código em blocos (como loops, condicionais e funções) sem o conceito de objetos. Abaixo, uma comparação entre os dois paradigmas:

Aspecto Programação Estruturada Programação Orientada a Objetos
Estrutura Baseada em funções e procedimentos. Baseada em objetos e classes.
Organização de Dados Dados e funções são separados. Dados (atributos) e comportamentos (métodos) são agrupados em objetos.
Reutilização Reutilização via funções repetitivas. Reutilização via herança e polimorfismo.
Manutenção Mais difícil em sistemas grandes, devido à falta de encapsulamento. Mais fácil, pois o encapsulamento e a modularidade organizam melhor o código.
Exemplo de Código Funções que manipulam variáveis globais ou locais. Classes que encapsulam dados e métodos relacionados.
Exemplo Prático Um programa para calcular salários usando funções separadas. Um sistema de RH com uma classe Funcionario que contém atributos (salário, nome) e métodos (calcularSalario, promover).

Exemplo em Java (POO)

01public class Funcionario {
02 private String nome;
03 private double salario;
04
05 public Funcionario(String nome, double salario) {
06 this.nome = nome;
07 this.salario = salario;
08 }
09
10 public void aumentarSalario(double aumento) {
11 salario += aumento;
12 System.out.println(“Novo salário de ” + nome + “: ” + salario);
13 }
14
15 public static void main(String[] args) {
16 Funcionario func = new Funcionario(“João”, 2000);
17 func.aumentarSalario(500);
18 }
19}

Exemplo Equivalente em Programação Estruturada (em linguagem C)

01#include <stdio.h>
02#include <string.h>
03
04struct Funcionario {
05 char nome[50];
06 double salario;
07};
08
09void aumentarSalario(struct Funcionario *f, double aumento) {
10 f->salario += aumento;
11 printf(“Novo salário de %s: %.2f\n”, f->nome, f->salario);
12}
13
14int main() {
15 struct Funcionario func = {“João”, 2000};
16 aumentarSalario(&func, 500);
17 return 0;
18}

Vantagens da POO sobre a Programação Estruturada

  • Modularidade: O código é organizado em classes, facilitando a manutenção e expansão.
  • Reutilização: Herança e polimorfismo permitem reutilizar código de forma eficiente.
  • Abstração do Mundo Real: Modelar entidades como objetos torna o desenvolvimento mais intuitivo.
  • Segurança: O encapsulamento protege os dados contra acessos indevidos.

Quando Usar Cada Paradigma?

  • Programação Estruturada: Ideal para programas pequenos, scripts ou sistemas com lógica simples, onde a overhead da POO não é necessária.
  • POO: Indicada para sistemas complexos, grandes projetos ou aplicações que exigem manutenção contínua, como sistemas empresariais, jogos ou aplicativos web.

1.3 Classes e objetos.

O que são Classes e Objetos?

Na Programação Orientada a Objetos (POO), uma classe é como um molde ou blueprint que define as características (atributos) e comportamentos (métodos) de um tipo de entidade. Um objeto é uma instância dessa classe, ou seja, um elemento concreto criado a partir do molde, com valores específicos para seus atributos.

Pense em uma classe como a planta de uma casa, que descreve a estrutura (quartos, portas, janelas), e o objeto como uma casa real construída a partir dessa planta, com detalhes específicos (como a cor das paredes ou o endereço).

Estrutura de uma Classe em Java

Uma classe em Java é definida usando a palavra-chave class, seguida pelo nome da classe. Ela pode conter:

  • Atributos: Variáveis que armazenam os dados do objeto.
  • Métodos: Funções que definem os comportamentos do objeto.
  • Construtores: Métodos especiais usados para criar objetos.

Exemplo Básico

01public class Carro {
02 private String marca;
03 private int velocidade;
04
05 public Carro(String marca, int velocidade) {
06 this.marca = marca;
07 this.velocidade = velocidade;
08 }
09
10 public void acelerar() {
11 velocidade += 10;
12 System.out.println(“O carro da marca ” + marca + ” está a ” + velocidade + ” km/h”);
13 }
14}

Criando e Usando Objetos

Um objeto é criado a partir de uma classe usando a palavra-chave new. Após a criação, você pode acessar os atributos e métodos do objeto usando o operador de ponto (.).

Exemplo de Criação de Objeto

01public class Main {
02 public static void main(String[] args) {
03 // Criando um objeto da classe Carro
04 Carro meuCarro = new Carro(“Toyota”, 0);
05
06 // Acessando atributos
07 System.out.println(“Marca: ” + meuCarro.marca);
08
09 // Chamando método
10 meuCarro.acelerar();
11 }
12}

Saída Esperada

Marca: Toyota
O carro da marca Toyota está a 10 km/h

Características Importantes

  • Instanciação: O processo de criar um objeto a partir de uma classe.
  • Estado: Representado pelos valores dos atributos de um objeto (ex.: marca = “Toyota”, velocidade = 0).
  • Comportamento: Definido pelos métodos que o objeto pode executar (ex.: acelerar()).
  • Identidade: Cada objeto é único, mesmo que tenha os mesmos valores de atributos que outro objeto da mesma classe.

Benefícios de Usar Classes e Objetos

  • Organização: Agrupa dados e comportamentos relacionados em uma única estrutura.
  • Reutilização: Uma classe pode ser usada para criar múltiplos objetos com características semelhantes.
  • Modelagem do Mundo Real: Facilita representar entidades como pessoas, carros ou contas bancárias de forma intuitiva.

Exemplo Prático

Imagine uma classe Aluno para um sistema escolar:

01public class Aluno {
02 // Atributos
03 private String nome;
04 private double nota;
05
06 // Construtor
07 public Aluno(String nome, double nota) {
08 this.nome = nome;
09 this.nota = nota;
10 }
11
12 // Método
13 public void verificarAprovacao() {
14 if (nota >= 7.0) {
15 System.out.println(nome + ” foi aprovado com nota ” + nota);
16 } else {
17 System.out.println(nome + ” foi reprovado com nota ” + nota);
18 }
19 }
20
21 public static void main(String[] args) {
22 Aluno aluno1 = new Aluno(“Ana”, 8.5);
23 Aluno aluno2 = new Aluno(“João”, 5.0);
24 aluno1.verificarAprovacao();
25 aluno2.verificarAprovacao();
26 }
27}

Saída Esperada

Ana foi aprovado com nota 8.5
João foi reprovado com nota 5.0

2. Encapsulamento

2.1 O que é Encapsulamento?

Encapsulamento é um dos pilares da Programação Orientada a Objetos (POO) que consiste em proteger os dados de uma classe, controlando como eles são acessados ou modificados. Em Java, isso é feito usando modificadores de acesso (como private) e fornecendo métodos públicos (getters e setters) para interagir com os atributos. O objetivo é garantir a segurança e a integridade dos dados, além de promover um código mais organizado e fácil de manter.

Pense no encapsulamento como uma cápsula que protege o conteúdo interno, permitindo acesso apenas por meios controlados.

Componentes do Encapsulamento

  1. Modificadores de Acesso:
    • private: Atributos ou métodos só podem ser acessados dentro da própria classe.
    • public: Atributos ou métodos acessíveis de qualquer lugar.
    • protected: Acessível dentro do mesmo pacote ou em subclasses (via herança).
    • (padrão, sem modificador): Acessível apenas no mesmo pacote.
  2. Getters e Setters:
    • Getters: Métodos públicos que retornam o valor de um atributo privado.
    • Setters: Métodos públicos que definem ou atualizam o valor de um atributo privado, muitas vezes com validações.
  3. Construtores:
    • Métodos especiais usados para inicializar objetos, garantindo que os atributos tenham valores válidos desde a criação.

Benefícios do Encapsulamento

  • Proteção dos dados: Evita alterações indevidas nos atributos.
  • Flexibilidade: Permite mudar a implementação interna sem afetar o código externo.
  • Validação: Setters podem incluir regras para garantir valores válidos.
  • Manutenção: Facilita a identificação e correção de erros.

Exemplo Prático em Java

Vamos criar uma classe ContaBancaria que usa encapsulamento para proteger o saldo e o titular da conta.

01public class ContaBancaria {
02 // Atributos privados
03 private String titular;
04 private double saldo;
05
06 // Construtor
07 public ContaBancaria(String titular, double saldoInicial) {
08 this.titular = titular;
09 if (saldoInicial >= 0) {
10 this.saldo = saldoInicial;
11 } else {
12 this.saldo = 0;
13 System.out.println(“Saldo inicial inválido. Definido como 0.”);
14 }
15 }
16
17 // Getter para titular
18 public String getTitular() {
19 return titular;
20 }
21
22 // Setter para titular
23 public void setTitular(String novoTitular) {
24 if (novoTitular != null && !novoTitular.trim().isEmpty()) {
25 this.titular = novoTitular;
26 } else {
27 System.out.println(“Nome do titular inválido.”);
28 }
29 }
30
31 // Getter para saldo
32 public double getSaldo() {
33 return saldo;
34 }
35
36 // Método para depositar
37 public void depositar(double valor) {
38 if (valor > 0) {
39 saldo += valor;
40 System.out.println(“Depósito de ” + valor + ” realizado. Saldo atual: ” + saldo);
41 } else {
42 System.out.println(“Valor de depósito inválido.”);
43 }
44 }
45
46 // Método para sacar
47 public void sacar(double valor) {
48 if (valor > 0 && valor <= saldo) {
49 saldo -= valor;
50 System.out.println(“Saque de ” + valor + ” realizado. Saldo atual: ” + saldo);
51 } else {
52 System.out.println(“Saque inválido: valor inválido ou saldo insuficiente.”);
53 }
54 }
55
56 public static void main(String[] args) {
57 // Criando um objeto
58 ContaBancaria conta = new ContaBancaria(“Maria”, 1000);
59
60 // Usando métodos públicos
61 System.out.println(“Titular: ” + conta.getTitular());
62 conta.depositar(500);
63 conta.sacar(200);
64 conta.setTitular(“Ana”);
65 System.out.println(“Novo titular: ” + conta.getTitular());
66 conta.sacar(2000); // Tentativa de saque inválido
67 }
68}

Saída Esperada

Titular: Maria
Depósito de 500 realizado. Saldo atual: 1500.0
Saque de 200 realizado. Saldo atual: 1300.0
Novo titular: Ana
Saque inválido: valor inválido ou saldo insuficiente.

Explicação do Exemplo

  • Atributos privados: titular e saldo só podem ser acessados dentro da classe.
  • Construtor: Garante que o saldo inicial seja válido (não negativo).
  • Getters e Setters: Controlam o acesso e a modificação do titular e do saldo, com validações (ex.: titular não pode ser vazio).
  • Métodos públicos: depositar e sacar incluem lógica para evitar operações inválidas, como depósitos negativos ou saques acima do saldo.

Boas Práticas

  • Sempre use atributos private para proteger os dados, a menos que haja uma razão específica para outro modificador.
  • Inclua validações nos setters e métodos que alteram atributos.
  • Evite setters desnecessários se o atributo não deve ser modificado após a criação do objeto.
  • Nomeie getters e setters de forma clara (ex.: getSaldo, setSaldo).
  • Use construtores para inicializar objetos com valores válidos.

Exercício Prático

Crie uma classe Produto com atributos privados nome e preco. Implemente:

  • Um construtor que inicializa os atributos, garantindo que o preço seja positivo.
  • Getters e setters com validações (ex.: nome não pode ser vazio).
  • Um método para aplicar um desconto, que só aceita valores de desconto entre 0 e 50%.

3. Herança

Aguarde…

4. Polimorfismo

Aguarde…

5. Abstração e Classes Avançadas

Aguarde…

6. Tratamento de Exceções e Boas Práticas

Aguarde…

7. Conclusão

Aguarde…