O que é programação orientada a objetos?
Introdução
No dia-a-dia do desenvolvimento é comum ouvirmos o termo "Paradigma de programação", e por mais que você não o escute tanto no seu meio, o conhecimento sobre do que se trata esse termo é essencial.
Conheça-o um pouco melhor abaixo. Bem-vindo, internauta!
Conceito
Um paradigma é uma forma de lidar com um problema. Um paradigma de programação é uma forma de lidar com os problemas envolvendo programação. Vamos a um exemplo utilizando o mundo real:
Vida real
Suponhamos que você precise levar um piano do térreo para o terceiro andar de um edifício. Você para e analisa de que formas pode realizar isso: Carregando-o no braço por vários lances de escada até o terceiro andar; levando-o em um carrinho de mão; desmontando-o na porta e montando todas as peças no final; colocando um motor no top do prédio que tracionaria o piano até o terceiro andar; chamando um guindaste; etc.
Como você pode ver, há varias forma de se resolver um mesmo problema, e na programação não é diferente. Vamos a um exemplo no universo da programação:
Programação
Com a diversidade de linguagens que encontramos disponíveis atualmente, temos uma quantidade satisfatória de paradigmas que nos são muito úteis a depender do problema que temos. Algumas linguagens resolvem problemas de front-end, outras de back-end, algumas ainda são fullstack; algumas são mais adequadas para desenvolvimento web, outras para plataforma Windows, outras ainda para a criação de compiladores; algumas são ótimas para agilizar o desenvolvimento do código, outras buscam ter uma escrita/sintaxe simples, outras ainda resolvem problemas de outras linguagens mais antigas.
Mas onde entra a orientação a objetos?
A orientação a objetos é um dos paradigmas mais utilizados hoje. Ela veio para otimizar o desenvolvimento de código dos sistemas atuais, que têm se tornado cada vez mais complexos e maiores.
Na sua abordagem consistem 4 conceitos fundamentais: abstração, herança, polimorfismo e encapsulamento.
Ao realizarmos a abstração de um objeto (também conhecido como classe) ao nosso código, estamos atribuindo a ele uma serie de características (também chamadas de parâmetros), ele pode executar ações (também chamadas de métodos) e interagir com outros objetos. Ou seja, na orientação a objetos criamos classes que possuem parâmetros e métodos, que podem interagir com outras classes.
Podemos criar classes dentro de classes (sub-classes). As classes superiores compartilham parâmetros e métodos com as sub-classes, e esse comportamento se chama herança. As sub-classes podem vir a ter novas características, ou mesmo alterar parâmetros ou métodos herdados, a depender do contexto em que são inseridos (o que se chama de polimorfismo).
Bem como, podemos adicionar uma camada de abstração entre a saída e entrada de dados (conhecida como encapsulamento). Por exemplo, ao adicionar um método que seja mediador entre aquilo que eu peço (utilizar os recursos do objeto) e aquilo que eu quero (valor do parâmetro ou o resultado de um método).
Quando encontramos essas 4 características fundamentais (abstração, herança, polimorfismo e encapsulamento) em um programa estamos lidando com uma aplicação orientada a objetos.
Além das características essenciais da orientação a objetos, temos algumas vantagens a mais que valem a pena serem citadas:
- O sistema se parece com algo mais próximo ao que pode ser observado na vida real;
- A reutilização de código é melhor feita, e hoje ela é essencial. Reusar o código faz com que um sistema tenha menos linhas e seja desenvolvido mais rapidamente;
- Torna diferentes partes do código mais independentes umas das outras, como módulos;
- Fácil leitura, manutenção e atualização;
- Facilita a criação de bibliotecas.
Apesar de diversas vantagens, esse paradigma possui algumas desvantagens, sendo a mais latente a maior lentidão na execução do software, visto que, pelas inferências do próprio modelo, um código orientado a objetos faz muito mais desvios do que um código funcional. Porém, tal fraqueza é quase imperceptível graças ao grande poder computacional que temos hoje.
Exemplo prático
Para demonstrar as diferenças entre os dois modelos de programar, eu preparei 2 exemplos utilizando Python (linguagem multiparadigma, isto é: pode ser escrita em mais de uma forma) que mostraram como ambos os métodos encaram o mesmo problema.
Abaixo temos o exemplo de um programa de calculadora que utiliza uma programação funcional:
# ================== INÍCIO =================== while True: # Mensagem de boas-vindas print('\ Inicie seus cálculos!\n\ =====================\n') # Define o primeiro numero da operação num1 = '' # Solicita que o usuário digite o número natural while not num1.isnumeric(): num1 = input('1° Número: ') # Sai do código se o usuário digitar 's' if num1 == 's': exit() # Define a operação ope = '' # Solicita que o usuário digite uma operação válida while ope not in {'+','-','*','/'}: ope = input(f'Um operador(+,-,*,/):\n{num1} ') # Sai do código se o usuário digitar 's' if ope == 's': exit() # Mensagem de erro elif ope not in {'+','-','*','/'}: print("\nEntre com um operador válido, engraçadinho\n") # Define o segundo numero da operação num2 = '' # Solicita que o usuário digite o número natural while not num2.isnumeric(): num2 = input(f'2° Número: {num1} {ope} ') # Sai do código se o usuário digitar 's' if num2 == 's': exit() # Converte as entradas numéricas para números de ponto flutuante num1 = float(num1) num2 = float(num2) # Realiza as operações e as mostra no console if ope == '+': print(f"\nResultado:", num1 + num2,"\n") elif ope == '-': print(f"\nResultado:", num1 - num2,"\n") elif ope == '*': print(f"\nResultado:", num1 * num2,"\n") elif ope == '/': print(f"\nResultado:", num1 / num2,"\n") else: pass # ================== FIM ===================
Agora, veremos um código com o mesmo comportamento, porém orientado a objetos:
# ================== INÍCIO =================== class Calculadora: # Diz ao programa para criar um objeto nomeador Calculadora def __init__(self): # Informa as características básicas do objeto (também chamado de Construtor) pass def run(self): # Define um método (nosso algoritmo) while True: self.saudacao() verificado = False while verificado == False: termo = 1 valor_para_avaliar = self.entrada(termo) verificado = self.verificador_numerico(valor_para_avaliar) num1 = verificado verificado = False while verificado == False: termo = 2 valor_para_avaliar = self.entrada(termo) verificado = self.verificador_operacao(valor_para_avaliar) ope = verificado verificado = False while verificado == False: termo = 3 valor_para_avaliar = self.entrada(termo) verificado = self.verificador_numerico(valor_para_avaliar) num2 = verificado if ope == '+': # Verifica se é uma soma self.soma(num1,num2) elif ope == '-': # Verifica se é uma subtração self.subtracao(num1,num2) elif ope == '*': # Verifica se é uma multiplicação self.multiplicacao(num1,num2) elif ope == '/': # Verifica se é uma divisão self.divisao(num1,num2) else: print("ERROR") def saudacao(self): # Sauda ao usuário print('\ Inicie seus cálculos!\\n\ =====================\n') def entrada(self,termo): # Recebe a entrada do usuário if termo == 1: valor_digitado = input("Digite um número ou [s]air: ") if termo == 2: valor_digitado = input("Escolha um operador (+,-,/,*) ou [s]air: ") if termo == 3: valor_digitado = input("Digite outro número ou [s]air: ") return valor_digitado def verificador_numerico(self, valor_entrado): # Verifica se o valor digitado é numérico (Natural) if valor_entrado == 's': exit() elif valor_entrado.isnumeric(): return float(valor_entrado) else: return False def verificador_operacao(self, valor_entrado): # Verifica se o valor digitado é uma operação válida if valor_entrado == 's': exit() elif valor_entrado not in {'+','-','*','/'}: return False else: return valor_entrado def soma(self, valor_a, valor_b): # Realiza a soma dos valores entrados return print(valor_a + valor_b) def subtracao(self, valor_a, valor_b): # Realiza a subtração dos valores entrados return print(valor_a - valor_b) def multiplicacao(self, valor_a, valor_b): # Realiza a multiplicação dos valores entrados return print(valor_a * valor_b) def divisao(self, valor_a, valor_b): # Realiza a divisão dos valores entrados return print(valor_a / valor_b) bolinha = Calculadora() # Instância a classe bolinha.run() # Chama o método 'run()', que será o nosso algoritmo. # ================== FIM ===================
Observações
- Perceba que o código do estruturado a funções flui de cima para baixo, enquanto o orientado a objetos faz muito mais desvios;
- Note que, no segundo código, todos os métodos estão muito bem definidos e separados, tornando-o mais organizado;
- Verifique que cada método executa uma função específica, o que torna o objeto bem mais robusto;
- Seria possível ainda agrupar métodos semelhantes criando sub-classes, o que tornaria o código bem mais organizado;
- O único método utilizado pelo programa é o 'run()', mas poderíamos chamar muito mais métodos se escrevêssemos o algoritmo fora do objeto.
Conclusão
Como pudemos ver, a utilização do paradigma de orientação a objetos pode representar comportamentos simples como o de uma calculadora, porém o seu uso é muito mais aplicado a sistemas mais complexos, um sistema completo de gerencia de loja, por exemplo. Cada funcionário/função seria um objeto, cada função possui características especificas (atributos), e dentro do sistema pode realizar certas ações (métodos).
Enfim, eu espero que vocês tenham conseguido entender. Para qualquer dúvida, dica, sugestão ou crítica, por favor, utilize o campo dos comentários. Muito obrigado e até mais!
Referência:
https://pt.m.wikipedia.org/wiki/Paradigma_de_programação
https://blog.betrybe.com/tecnologia/paradigmas-de-programacao/
https://www.devmedia.com.br/os-4-pilares-da-programacao-orientada-a-objetos/9264
Comentários
Postar um comentário