Paradigmas de Programação

Paradigmas de Programação
paradigma e a positividade de conhecer e não temer

Fala, skillers! Hoje vamos falar sobre paradigmas de programação. "Paradigma" parece uma daquelas palavras que só aparecem em provas de filosofia, mas relaxa que vou te mostrar como isso é essencial para a nossa arte de codar.

Imperativo

No paradigma imperativo, você é o chefe e o computador é o estagiário que segue suas ordens à risca. Você diz o que fazer e como fazer. É como se você estivesse dando um passo a passo de como preparar um miojo gourmet.

Exemplos

  1. Linguagem C


No C, você tem que ser bem específico sobre o que quer fazer. Você declara variáveis, modifica seus valores e controla o fluxo do programa passo a passo.

C Programming Language PNG and C Programming Language Transparent Clipart  Free Download. - CleanPNG / KissPNG
#include <stdio.h>

int main() {
    int num = 15; // Declara uma variável num e inicializa com 15
    num = num + 10; // Soma 10 ao valor atual de num
    printf("%d", num); // Imprime o valor de num, que agora é 25
    return 0; // Encerra o programa com sucesso
}
  1. Python
The Python Logo | Python Software Foundation

Python é conhecido por ser super legível. Aqui, definimos uma função que faz o trabalho e a chamamos com o número 15. Python cuida de muitos detalhes para você, como gerenciamento de memória.

num = 15
soma = num + 10

print soma # mostrará 25


3. Javascript

JavaScript Logo , symbol, meaning, history, PNG, brand


JavaScript é a linguagem que domina os navegadores. Aqui, também estamos fazendo uma operação simples de adição e exibindo o resultado no console.

let num = 15; // Declara uma variável num e atribui 15 a ela
num += 10; // Usa o operador += para adicionar 10 ao valor atual de num
console.log(num); // Imprime o valor de num no console, que será 25

Em todas essas linguagens, estamos seguindo o paradigma imperativo: dizendo ao computador como fazer algo passo a passo. É como se estivéssemos dando uma receita de bolo para ele seguir. E aí, curtiu os exemplos? Qualquer coisa, só chamar que a gente descomplica mais! 🚀

Procedural

Aqui ainda é você quem manda, mas agora você organiza as tarefas em procedimentos ou funções. É tipo ter uma playlist para cada momento do seu dia.

O paradigma procedural é caracterizado pelo uso de procedimentos, também conhecidos como funções ou sub-rotinas, que contêm uma série de etapas computacionais a serem executadas. Vou fornecer exemplos em três linguagens de programação que suportam o paradigma procedural: C, Pascal e Python.

C Programming Language PNG and C Programming Language Transparent Clipart  Free Download. - CleanPNG / KissPNG
  1. C

C é uma linguagem de programação procedural clássica. Aqui está um exemplo simples de um procedimento em C que calcula a soma de dois números:

#include <stdio.h>

// Definição do procedimento
void soma(int a, int b) {
    int resultado = a + b;
    printf("A soma é: %d\n", resultado);
}

int main() {
    // Chamada do procedimento
    soma(5, 3);
    return 0;
}


Neste exemplo, soma é um procedimento que recebe dois inteiros, os soma e imprime o resultado.

  1. Pascal


Pascal é outra linguagem de programação procedural. Aqui está um exemplo de um procedimento em Pascal que realiza a mesma tarefa:

Pascal Tutorial
program Example;
uses crt;

// Definição do procedimento
procedure Soma(a, b: Integer);
var
  resultado: Integer;
begin
  resultado := a + b;
  WriteLn('A soma é: ', resultado);
end;

begin
  // Chamada do procedimento
  Soma(5, 3);
  ReadKey;
end.

Neste exemplo, Soma é um procedimento que toma dois parâmetros, calcula a soma e exibe o resultado.

The Python Logo | Python Software Foundation

  1. Python

Embora Python seja uma linguagem de programação de alto nível com suporte a múltiplos paradigmas, incluindo programação orientada a objetos e funcional, ela também pode ser usada de forma procedural. Aqui está um exemplo de uma função em Python que age como um procedimento:

# Definição da função
def soma(a, b):
    resultado = a + b
    print(f"A soma é: {resultado}")

# Chamada da função
soma(5, 3)

Neste exemplo, soma é uma função que recebe dois argumentos, calcula a soma e imprime o resultado. Em Python, as funções podem ser tratadas como procedimentos quando não retornam explicitamente um valor (ou seja, quando não há um return ou quando o return não tem um valor associado).

Esses exemplos demonstram o uso do paradigma procedural em diferentes linguagens de programação. Embora a sintaxe varie, o conceito fundamental de encapsular a lógica em blocos reutilizáveis é consistente entre elas.

Paradigma Imperativo

O paradigma imperativo é o mais básico dos paradigmas de programação e foca em como você faz as coisas, ou seja, como você chega a um resultado. Ele é caracterizado pelo uso de comandos para alterar o estado do programa. Você diz ao computador para realizar uma série de tarefas passo a passo. Este paradigma inclui conceitos como variáveis, loops e condicionais.

Exemplo em pseudocódigo imperativo:

inicialize total como 0
para cada número na lista:
    adicione o número ao total
mostre o total

Paradigma Procedural

O paradigma procedural é uma extensão do imperativo. Ele ainda diz ao computador como fazer as coisas, mas introduz o conceito de procedimentos ou funções — blocos de código que podem ser reutilizados. Isso permite que você estruture melhor o seu código e o torne mais modular e fácil de manter. No procedural, você ainda está preocupado com o estado e como as coisas são feitas, mas você organiza seu código em procedimentos que podem ser chamados várias vezes.

Exemplo em pseudocódigo procedural:

procedimento calculeTotal(lista de números):
    inicialize total como 0
    para cada número na lista:
        adicione o número ao total
    retorne total

total = calculeTotal(lista de números)
mostre total

A principal diferença é que, enquanto o imperativo pode ser considerado a base, o procedural é uma construção sobre essa base que introduz a ideia de dividir o código em unidades reutilizáveis chamadas procedimentos ou funções. Isso ajuda a evitar repetições e torna o código mais organizado e fácil de entender.

Declarativo

O paradigma declarativo de programação é um estilo onde você escreve código que descreve o que você quer alcançar, em vez de como você quer alcançá-lo. Este paradigma contrasta com o estilo imperativo, onde o código precisa detalhar explicitamente os passos necessários para alcançar um resultado desejado.

Aqui estão três exemplos de uso do paradigma declarativo:

Ficheiro:Sql data base with logo.png

1. SQL para Bancos de Dados

SQL, ou Linguagem de Consulta Estruturada, é uma linguagem declarativa usada para gerenciar e recuperar informações de bancos de dados relacionais. Em vez de dizer ao computador como percorrer tabelas e dados, você declara o que deseja.

Exemplo:

SELECT nome, idade FROM usuarios WHERE pais = 'Brasil';

Este comando SQL declara que você deseja obter os nomes e idades dos usuários que estão no Brasil. O sistema de gerenciamento de banco de dados (SGBD) cuida de como essa operação será realizada.

2. HTML para Páginas Web

W3C HTML5 Logo

HTML, ou Linguagem de Marcação de Hipertexto, é uma linguagem declarativa usada para estruturar conteúdo na web. Você descreve a estrutura da página, e o navegador web cuida de renderizá-la.

Exemplo:

<p class="destaque">Bem-vindo ao meu site!</p>

Este trecho de HTML declara que há um parágrafo de texto que deve ser destacado (possivelmente com estilos definidos em CSS). O navegador interpreta essa marcação e exibe o conteúdo de acordo.

3. CSS para Estilização de Páginas Web

CSS - Wikipedia

CSS, ou Cascading Style Sheets, é uma linguagem declarativa usada para definir a apresentação de um documento escrito em HTML ou XML. Você declara como os elementos devem ser exibidos, e o navegador aplica esses estilos.

Exemplo:

.destaque {
  font-weight: bold;
  color: red;
}

Este CSS declara que qualquer elemento com a classe destaque deve ter o texto em negrito e colorido de vermelho. O navegador aplica esses estilos automaticamente onde a classe é usada.

Em todos esses exemplos, o foco está em descrever o resultado desejado, não em como o computador deve chegar a esse resultado. Isso pode tornar o código mais fácil de ler e manter, pois você está trabalhando em um nível mais abstrato de pensamento.

Funcional

Inspirado na matemática, você trabalha com funções que transformam dados sem alterar o estado do mundo. É como se cada função fosse uma receita que sempre dá certo se você seguir os passos.

A programação funcional é um subtipo do paradigma declarativo que trata a computação como a avaliação de funções matemáticas e evita mudanças de estado e dados mutáveis. É baseada em funções puras, imutabilidade e funções de primeira classe.

Quando usar a programação funcional:

  1. Cálculos Matemáticos Complexos: Devido à sua proximidade com a matemática, a programação funcional é adequada para sistemas que requerem uma alta confiabilidade em cálculos complexos.
  2. Programas Concorrentes ou Paralelos: A imutabilidade dos dados facilita a execução de programas em ambientes concorrentes ou paralelos, pois não há preocupações com condições de corrida.
  3. Sistemas com Fluxos de Dados Complexos: A capacidade de compor funções torna mais fácil gerenciar fluxos de dados complexos e operações de transformação de dados.
  4. Desenvolvimento de Software Reativo: Para aplicações que requerem um alto grau de reatividade a eventos, como interfaces de usuário ou sistemas em tempo real.

Por que usar a programação funcional:

  1. Código Mais Limpo e Expressivo: As funções puras e a composição de funções podem levar a um código mais conciso e fácil de entender.
  2. Facilidade de Teste e Depuração: Funções puras são mais fáceis de testar e depurar, pois não dependem nem alteram o estado externo.
  3. Menos Bugs: A imutabilidade e as funções puras reduzem os efeitos colaterais, o que pode levar a menos bugs.
  4. Reusabilidade de Código: As funções de alta ordem e a composição de funções podem aumentar a reusabilidade do código.

Exemplos de linguagens funcionais:

  1. Haskell:

    • É uma linguagem puramente funcional com tipagem estática.
    • Exemplo:
      -- Define uma função que calcula o quadrado de um número
      square x = x * x
      
      -- Usa a função map para aplicar a função square a uma lista de números
      main = print (map square [1, 2, 3, 4, 5])
      
      Este código define uma função square e a aplica a uma lista de números, retornando uma nova lista com os quadrados dos números originais.
  2. Erlang:

    • Usada principalmente para sistemas de telecomunicações, é conhecida por sua capacidade de lidar com sistemas concorrentes e distribuídos.
    • Exemplo:
      % Define uma função que calcula o fatorial de um número
      factorial(0) -> 1;
      factorial(N) -> N * factorial(N-1).
      
      Este código usa o padrão de correspondência para definir a função fatorial de maneira recursiva.
  3. Scala:

    • Combina programação orientada a objetos e funcional, rodando na JVM (Java Virtual Machine).
    • Exemplo:
      // Define uma função anônima que calcula o quadrado de um número e a aplica a uma lista
      val numbers = List(1, 2, 3, 4, 5)
      val squaredNumbers = numbers.map(n => n * n)
      println(squaredNumbers)
      
      Este código usa uma função anônima para calcular o quadrado de cada número em uma lista e imprimir o resultado.
  4. Clojure:

    • É uma linguagem funcional moderna que também roda na JVM.
    • Exemplo:
      ;; Usa a função map com uma função anônima para calcular o quadrado de números
      (println (map #(Math/pow % 2) [1 2 3 4 5]))
      
      Este código usa uma função anônima para calcular o quadrado de números em uma lista.
  5. F#:

    • É uma linguagem funcional para a plataforma .NET.
    • Exemplo:
      // Define uma função que calcula o quadrado de um número
      let square x = x * x
      
      // Aplica a função square a uma lista de números
      [1; 2; 3; 4; 5] |> List.map square |> printfn "%A"
      
      Este código define uma função square e a aplica a uma lista de números, imprimindo os quadrados dos números originais.
  6. Javascript:

  • React JS é uma biblioteca JavaScript para construir interfaces de usuário que também adota princípios da programação funcional, especialmente com a introdução de Hooks.
  • Exemplo:
 import React, { useState } from 'react';

   function Counter() {
     const [count, setCount] = useState(0);

     return (
       <div>
         <p>You clicked {count} times</p>
         <button onClick={() => setCount(count + 1)}>
           Click me
         </button>
       </div>
     );
   }

  1. Programação Funcional em Ruby
  • Ruby não é uma linguagem funcional por natureza, mas permite a programação funcional através de lambdas e procs.
  • Exemplo
 squared_numbers = [1, 2, 3, 4, 5].map { |n| n ** 2 }
 puts squared_numbers

Cada uma dessas linguagens oferece recursos únicos que as tornam adequadas para diferentes tipos de tarefas de programação funcional. A escolha da linguagem muitas vezes depende do ecossistema em que você está trabalhando (por exemplo, JVM, .NET) e das preferências pessoais ou da equipe.

Lógico

Agora, a coisa fica Sherlock Holmes. No paradigma lógico, você descreve o problema e o computador vira detetive para resolver o caso. Você diz o que precisa ser resolvido, e ele encontra a solução.

Características do Paradigma Lógico

  • Declaratividade: Os programas são escritos de forma declarativa, especificando o "o quê" em vez do "como".
  • Imutabilidade: Os fatos em um programa lógico não mudam uma vez que são estabelecidos.
  • Backtracking: Muitas linguagens lógicas usam backtracking para encontrar soluções, revertendo decisões anteriores para explorar diferentes caminhos lógicos.
  • Recursão: A recursão é uma ferramenta natural e poderosa em linguagens lógicas, permitindo definições concisas de problemas complexos.

Prolog

Prolog, que significa "Programação em Lógica", é uma das linguagens de programação lógica mais conhecidas. Ela é usada principalmente em sistemas de inteligência artificial e processamento de linguagem natural.

% Definição de parentesco
parent(philip, charles).
parent(queen_mother, elizabeth).

% Regra para encontrar um avô
grandparent(X, Y) :- parent(X, Z), parent(Z, Y).

% Consulta: Quem é o avô de Elizabeth?
?- grandparent(X, elizabeth).

Datalog

Datalog é uma linguagem de consulta e uma subconjunto do Prolog, frequentemente usada em bancos de dados e sistemas de informação.

% Fatos
likes(mary, food).
likes(john, football).
likes(susan, food).

% Regra
friend(X, Y) :- likes(X, Z), likes(Y, Z), X != Y.

% Consulta: Quem são amigos por gostarem das mesmas coisas?
?- friend(X, Y).

Mercury

Mercury é uma linguagem de programação lógica funcional que visa ser mais eficiente e fácil de usar do que o Prolog tradicional.

% Fato
likes("Alice", reading).
likes("Bob", chess).
likes("Carol", reading).

% Regra
friend(X, Y) :- likes(X, Activity), likes(Y, Activity), X \= Y.

% Consulta: Quem são amigos baseados em atividades comuns?
?- friend(Alice, Friend).

O paradigma lógico oferece uma abordagem única e poderosa para a resolução de problemas, permitindo que os programadores expressem complexidades de maneira concisa e clara. Ele é especialmente útil em campos como a inteligência artificial, onde a capacidade de representar e manipular conhecimento é fundamental.

Programação Orientada a Objetos

No paradigma orientado a objetos, você pensa em tudo como se fossem objetos do mundo real, com características e ações próprias. É como ter um time, onde cada jogador tem uma função específica.

Programação Orientada a Objetos (POO):

Conceitos e Aplicações

A Programação Orientada a Objetos (POO) é um paradigma de programação baseado no conceito de "objetos", que podem conter dados na forma de campos, frequentemente conhecidos como atributos, e código, na forma de procedimentos, frequentemente conhecidos como métodos. Um dos principais benefícios da POO é a capacidade de aumentar a reutilização de código e tornar os modelos de software mais compreensíveis.

Conceitos Fundamentais da POO

Abstração

A abstração é o processo de ocultar a complexidade real de um sistema, expondo apenas as partes necessárias. Em POO, isso é feito usando classes que representam tipos abstratos de objetos do mundo real.

Em Java, a abstração é frequentemente alcançada usando classes abstratas ou interfaces. Uma classe abstrata não pode ser instanciada por si só e é destinada a ser subclassificada, enquanto interfaces podem ser usadas para definir um contrato que outras classes implementarão.

// Exemplo de uma classe abstrata em Java
public abstract class Vehicle {
    private String brand;

    // Método abstrato
    public abstract void honk(); // Os veículos honram de formas diferentes

    // Métodos concretos
    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }
}

// Classe concreta que estende a classe abstrata
public class Car extends Vehicle {
    @Override
    public void honk() {
        System.out.println("Beep beep!");
    }
}

Encapsulamento

Encapsulamento é o conceito de esconder o estado interno de um objeto e exigir que toda a interação seja realizada através de métodos. Isso protege a integridade dos dados e esconde a complexidade.

O encapsulamento em Java é realizado usando modificadores de acesso: private, protected, e public. Ao declarar os campos de uma classe como private, você restringe o acesso direto a eles, forçando o uso de métodos públicos para ler ou modificar esses campos (getters e setters).

public class Account {
    private double balance;

    // Getter
    public double getBalance() {
        return balance;
    }

    // Setter
    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
        }
    }

    public void withdraw(double amount) {
        if (amount <= balance) {
            balance -= amount;
        }
    }
}

Herança

Herança permite que uma classe herde características (métodos e atributos) de outra classe. A classe que herda é chamada de subclasse ou classe derivada, e a classe da qual se herda é chamada de superclasse ou classe base.

A herança é um recurso chave da POO que permite que uma nova classe adquira as propriedades e comportamentos de uma classe existente. Em Java, a herança é realizada usando a palavra-chave extends.

// Classe base ou superclasse
public class Animal {
    public void eat() {
        System.out.println("This animal eats food.");
    }
}

// Subclasse que herda de Animal
public class Dog extends Animal {
    public void bark() {
        System.out.println("The dog barks.");
    }
}

Polimorfismo

Polimorfismo é a capacidade de chamar o mesmo método em diferentes objetos e cada objeto responder de acordo com a classe a que pertence.

O polimorfismo permite que objetos sejam tratados como instâncias de sua classe base em vez de sua classe real. Em Java, isso significa que uma referência de superclasse pode referir-se a um objeto de qualquer subclasse.

public class Shape {
    public void draw() {
        System.out.println("Drawing a shape.");
    }
}

public class Circle extends Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a circle.");
    }
}

public class Square extends Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a square.");
    }
}

public class Main {
    public static void main(String[] args) {
        Shape shape1 = new Circle();
        Shape shape2 = new Square();

        shape1.draw(); // Saída: Drawing a circle.
        shape2.draw(); // Saída: Drawing a square.
    }
}

Neste exemplo de polimorfismo, o método draw() é sobrescrito nas subclasses Circle e Square, mas podemos chamar draw() em uma referência do tipo Shape. Em tempo de execução, o método apropriado é chamado com base no tipo real do objeto referenciado.

Quando usar POO

A POO é ideal quando você tem um conjunto complexo de interações e relacionamentos entre entidades, e você quer modelar seu software de maneira próxima à representação do mundo real. É útil em sistemas grandes e complexos que requerem manutenção e escalabilidade a longo prazo.

Exemplos em Diferentes Linguagens

Smalltalk (A Mãe da POO)

"Definição de uma classe Pessoa"
Person class
   superclass: Object
   instanceVariableNames: 'name age'

"Definição de métodos"
Person methodsFor: 'acessando'
getName
   ^name

setName: aName
   name := aName.

getAge
   ^age

setAge: anAge
   age := anAge.

Java

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

Ruby

class Person
    attr_accessor :name, :age

    def initialize(name, age)
        @name = name
        @age = age
    end
end

Python

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def get_name(self):
        return self.name

    def set_name(self, name):
        self.name = name

    def get_age(self):
        return self.age

    def set_age(self, age):
        self.age = age

C++

class Person {
private:
    std::string name;
    int age;

public:
    Person(std::string name, int age) : name(name), age(age) {}

    std::string getName() const { return name; }
    void setName(const std::string &name) { this->name = name; }

    int getAge() const { return age; }
    void setAge(int age) { this->age = age; }
};

Cada um desses exemplos ilustra como uma classe Person pode ser definida em diferentes linguagens orientadas a objetos. Note que a sintaxe varia, mas os conceitos fundamentais de POO são consistentes em todas elas.

E aí, qual escolher?

Ei, não tem essa de melhor ou pior. Cada paradigma tem seu momento e seu problema para resolver. É como música: tem hora pra curtir um rock, um rap ou um sertanejo. Depende do problema que você tá tentando resolver.

Então é isso, galera. Programar é escolher a melhor conjunto de ferramentas pra resolver seu problema. E lembre-se: o importante é chegar lá, não importa se é de skate, de bike ou de patinete. Fica a dica e bora codar! 🤘

Read more