← voltar para guias
IntermediárioDesenvolvimento

Qual é a diferença entre programação orientada a objetos e funcional?

Compara os paradigmas de programação orientada a objetos (POO) e funcional, explicando conceitos como mutabilidade, imperativo vs declarativo e quando usar cada um.

Primeiro, imagina que você precisa ir até a casa de ume amigue que mora na mesma cidade. Dá pra ir de carro, ônibus, metrô, trem, bicicleta ou a pé. E dentro de algumas dessas opções, tem mais de uma forma , de carro, por exemplo, pode ser seu carro, carona ou aplicativo. Cada jeito tem suas vantagens e desvantagens de preço, tempo, distância, segurança, conforto, etc.

A mesma lógica vale pra programação. Tipos diferentes de programação buscam resolver problemas diferentes, e pra se adaptar melhor a cada objetivo, a forma de estruturar e organizar o código também muda.

É dessas diferentes estruturas que surgem os paradigmas de programação , grandes grupos de linguagens com características parecidas. Os dois principais são as linguagens orientadas a objeto e as linguagens funcionais.

Programação orientada a objeto (POO)

Primeiro, vamos falar sobre o tipo mais popular de programação, a programação orientada a objeto, ou POO.

A POO é baseada no conceito de objetos, que são representações de um dado. Um exemplo simples é um bolo. Um bolo tem o sabor da massa, da cobertura, cores, tamanho, quem fez, qual é o tamanho de cada pedaço,etc. Todos esses dados sobre o bolo podem ser representados em um único objeto, sendo esse o principal elemento nas linguagens orientadas à objeto.

Uma outra característica muito marcante nas linguagens orientadas a objeto é o foco mais no como, que no que. Em outras palavras, é mais importante o caminho para chegar em uma ação, que a ação em si.

Um exemplo disso é a adição de uma nova pessoa usuária. Em POO, a maior parte do processo seria a montagem de um objeto que represente essa nova pessoa, e todas as checagens nesse processo. Só no fim do fluxo que a adição seria feita de verdade. Então o foco foi mais direcionado à como fazer, do que à ação por si.

Exemplos de linguagens famosas que incluem programação orientada à objeto são Ruby, Scala, Java, Python,etc.

Programação funcional

A programação funcional por um outro lado é mais focada nas funções do que nos objetos, buscando criar um código mais limpo, e direto, com uma menor complexidade que a programação orientada à objetos. Tanto que um dos conceitos da programação funcional são as funções puras.

As funções puras são funções que estão isoladas do resto do código, então independente de qualquer outro código que estiver fora do escopo delas, elas sempre vão dar os mesmo resultados. Algo que não pode ser garantido em linguagens orientadas à objeto por conta das propriedades que os objetos podem ter.

A vantagem por trás das funções puras é a simplicidade, e a segurança delas. Porque não tem nenhum objeto, ou classe que pode afetar a função, tendo a garantia que recebendo os mesmos inputs, o resultado sempre será o mesmo.

Exemplos de linguagens famosas que incluem programação funcional são Haskell, Elixir, Erlang, OCaml,etc.

Mutabilidade de variáveis

Em linguagens orientadas à objetos, por padrão, as variáveis são mutáveis, enquanto linguagens funcionais têm as variáveis imutáveis por padrão. Essa diferença vem por conta das funções puras, pois uma das filosofias da programação funcional é representar o retorno das funções como o "trabalho pronto", apenas atribuindo uma variável com esse valor.

Programação imperativa e declarativa

Programação orientada a objeto e programação funcional também se diferem na forma que organizamos o nosso código, com a POO sendo uma programação imperativa, enquanto a programação funcional sendo uma programação declarativa. Para mostrar essa diferença, vamos à um exemplo prático.

Vamos supor que temos uma lista de senhas, e que precisamos filtrar essas senhas para apenas as que tem mais de 9 caracteres. Em Javascript, de forma imperativa, poderíamos fazer isso da seguinte forma:

const senhas =[
"123456",
"senha",
"admin",
"feministech",
"minhasenha",
];
let senhasAprovadas = [];

for (let i = 0; i < senhas.length; i++) {
    const senha = senhas[i];
    if (senha.length >= 9){
    senhasAprovadas.push(senha);
    }
}

Tentando olhar esse código de forma mais profunda, ele faz esse processo de verificação e adição contando uma história, então primeiro é usado o for, passando item por item dessa lista. Para cada item, será verificado se o tamanho da senha é maior que 9 caracteres, e caso sim, essa senha será adicionada à uma lista de senhas aprovadas.

Essa forma de programar, colocando instruções que criam uma história, dependendo da outra é a forma imperativa. Essa palavra "imperativa" significa uma ordem, como "faça aquilo, depois aquilo, e depois isso".

Podemos também fazer um código com o mesmo resultado, mas de uma forma declarativa, dessa forma:

const senhasAprovadas = senhas.filter(senha => senha.length >= 9);

No código acima, usamos a função filter para filtrar todos os itens dessa lista de senhas, e mantendo apenas os itens que tiverem um número de caracteres maior que 9, removendo todo o resto da lista.

Essa forma mostrada acima é declarativa pois estamos nos preocupando apenas com o que estamos fazendo, não com como estamos fazendo todo esse processo, sendo essa a principal diferença entre programação imperativa e declarativa.

Exemplo prático: fatorial de um número

Agora vamos à um exemplo prático, vamos criar uma função que retorna o fatorial de um número, que é a multiplicação de todos os número antecessores a esse, até o número um.

Para criar essa função, em Javascript, com POO, podemos escrever essa função dessa forma:

function fatorial(numero) {
    if (numero === 0 || numero === 1)
        return 1;
      for (var i = num - 1; i >= 1; i--) {
        numero *= i;
      }
      return numero;

}

Analisando esse código, podemos ver que se esse número for 0, ou 1, o retorno será fixo em 1. Se não, será executado um for, indo do número, até 1, diminuindo esse valor, e a cada execução deste for, o número será multiplicado pelo seu valor, menos um. E depois será retornado o número fatorial.

Essa solução funciona, mas podemos resolver esse problema de outra forma, usando um conceito da programação funcional chamado de recursão.

function fatorial(numero) {
     if (numero < 0) 
            return -1;
      else if (numero == 0) 
          return 1;
      else {
          return (numero * fatorial(num - 1));
      }

}

Analisando esse código, podemos ver que existem 3 possibilidades: Se o número for menor que zero, se o número for igual a zero, ou se o número é nenhuma das duas opções (maior que zero).

Caso o número seja menor que zero, seu fatorial será -1, caso seja igual a zero, seu fatorial será 1, e se caso o número for maior que zero, é usada uma função de recursão, onde será retornado o número, vezes o resultado dessa mesma função, com o número subtraído de um.

É difícil entender esses conceitos de recursão no começo, mas é basicamente usar uma função dentro da mesma função, evitando ter que usar loops como for e while sem necessidade.

Na maioria das vezes usar recursividade em JS ou linguagens semelhantes pode não ser uma boa ideia, pois elas não lidam bem com isso a nível de máquina virtual ou runtime, isso pode deixar o código lento e até mesmo estourar a pilha de execução, fechando o programa, ou travando a máquina.

Mas em linguagens de programação funcionais, esse código é perfeitamente adequado, e correto seguindo os padrões da linguagem. Um exemplo disso é que podemos criar uma função de fatorial usando recursão em Elixir, uma linguagem muito caracterizada pela programação funcional.

defmodule Factorial do
  def of(0), do: 1
  def of(n) when n > 0, do: n * of(n - 1)
end

Nesse caso, usar programação funcional (ou apenas conceitos de programação funcional, como a recursão) pode simplificar o código, tornando ele menor e mais legível. Mas caso precisássemos mexer com valores fora da função, ou com coisas que podem mudar de estado antes ou depois dessa função, e que poderiam mudar a sua execução, POO seria melhor nesses casos, garantindo mais segurança e flexibilidade.

Onde usar cada uma?

Como vimos, a POO e a programação funcional tem características bem diferentes, e por isso, cada uma pode ser utilizada em situações diferentes.

Para aplicações que exigem muitas classes, e muitas instâncias de objetos, como CRUD's, com classe para usuáries, posts, transações,etc. E pouca manipulação desses objetos, como apenas fazer verificações, escrever em um banco de dados, e retornar outro objeto, POO pode se encaixar perfeitamente, fornecendo todos os recursos que você precisa.

Enquanto para aplicações que exigem poucas variáveis, e variáveis com valores mais simples, como números, strings, ou listas, e muita manipulação nesses valores, como aplicações matemáticas, programação funcional pode se encaixar melhor que POO, garantindo que sempre quando o seu programa receber os mesmo valores de input, serão retornados os mesmo valores de output.

E além, caso você esteja utilizando uma linguagem mista, é possível usar ambos tipos de programações dentro de uma única aplicação.

Linguagens mistas

Existem linguagens que implementam diversos paradigmas de programação, como POO e programação funcional, ao mesmo tempo. Oferecendo ambas formas de programar em uma mesma linguagem, podendo até mesmo intercalar os dois tipos, ou até outros, em um mesmo código.

Exemplos de linguagens que são multiparadigma é Kotlin, Python, Javascript e C#.

Finalização

Nesse artigo exploramos juntas os conceitos de programação orientada a objetos e programação funcional, mostrando as diferenças e as funcionalidades de cada uma. Se você chegou até aqui sem ter entendido tudo de primeira , tá ótimo. Esses conceitos pedem tempo e prática, não um dom especial. Você não está atrasada, está no processo.

← voltar para o início