Conceitos de POO: abstração e encapsulamento

Afinal de contas, o que é Programação Orientada a Objetos (POO) e os conceitos de abstração e encapsulamento? Para começar, definirei de onde ela veio. Essa forma de programação é chamada de paradigma, na qual se diferencia principalmente do paradigma de programação estruturada. 

Quando comecei no mundo da programação, e imagino que com você também tenha sido assim, aprendemos sobre lógica de programação com estrutura de controles de fluxo e estruturas de repetições. Eles são conhecidos também pelas palavras reservadas das linguagens que geralmente são: if, else, switch, for e while. 

Essas estruturas, junto com a sequencialidade da execução dos programas e a execução do programa em uma única rotina, formam o paradigma de programação estruturada. 

Esse tipo de programação se torna insuficiente para a resolução de programa reais e complexos, pois existe um acoplamento forte do código a ser desenvolvido.

A Orientação a Objetos surgiu para resolver esse tipo de problema, mas também para criar uma camada de abstração ao se desenvolver programas, imaginando que podemos criar objetos como uma metáfora para a nossa vida real. 

Conceitos de POO

Falando em abstração, aqui vão os quatro conceitos que formam a Programação Orientada a Objetos:

  • Abstração;
  • Encapsulamento;
  • Herança;
  • Polimorfismo.

Focarei em dois desses conceitos: abstração e encapsulamento. Para cada um escreverei uma breve explicação junto com um exemplo de código em TypeScript. 

Se você quiser reproduzir esses códigos eu sugiro utilizar o Playground, dessa forma você pode usar o TypeScript sem precisar instalar nada.

Abstração

Esse é o primeiro conceito que quero abordar, pois ele é em si o conceito de criação das classes e objetos. Esse conceito nos orienta a construir códigos que sejam relacionados com objetos da nossa vida real. 

Classes são os modelos ou moldes nos quais surgirão os objetos. As classes definem algumas propriedades e métodos que deverão fazer parte do objeto que derivar dela ou então, como dizemos, os objetos que serão instanciados a partir dela.

Aqui vai um código em TypeScript para criar uma classe de uma Candidatura e logo após a instanciação do objeto a partir dela. Vou criar um objeto desse tipo para tentar aplicar os conceitos de orientação a objetos a um problema real que desenvolvemos aqui na Coodesh. 

Como fazemos aqui não é exatamente o que farei neste artigo, mas ajuda a concretizar a aplicação desses conceitos:

class Candidatura {
    _pessoaCandidata: string;
    _vaga: string;
    _pretensaoSalarial: number;

    constructor(pessoaCandidata: string, vaga: string, pretensaoSalarial: number) {
        this._pessoaCandidata = pessoaCandidata;
        this._vaga = vaga;
        this._pretensaoSalarial = pretensaoSalarial;
    }

    enviarTesteTecnico(){
        console.log('Enviar email para ' + this._pessoaCandidata);
    }
}

Nesse código acima temos alguns conceitos muito importantes sobre a orientação a objetos. O primeiro é a declaração da classe Candidatura, esse é o nosso molde na qual todas as candidaturas deverão ser criadas. 

Nossa classe tem três propriedades, pessoaCandidata, vaga e pretensaoSalarial. Essas propriedades são as características que cada objeto deverá ter. Usando a linguagem TypeScript podemos definir os tipos dessas propriedades, as duas primeiras como string e a última como number.

Métodos 

Logo após a definição das propriedades temos a definição de dois métodos. Métodos são as ações que cada objeto deverá ter. 

O primeiro método, constructor, é um método especial, deve ter esse nome para promover a ação desejada. Ele é o método que será chamado no momento da instanciação de um objeto, por isso ele recebe três parâmetros e preenche as propriedades do objeto a ser criado. 

Perceba que usamos a palavra reservada this dentro da classe para atribuir um valor para o parâmetro dentro da classe. Essa palavra faz referência ao próprio objeto que será criado.

O segundo método criado é o método enviarTesteTecnico. Esse método simula o envio de um e-mail para a pessoa candidata. Deve-se chamar esse método quando quiser executar a ação de enviar o teste técnico. Dentro desse método certamente a lógica será mais complexa do que a atual, mas depois de implementada a lógica podemos enviar o teste técnico apenas chamando esse método, promovendo assim a abstração desse código.

No código acima apenas criamos nossa classe, mas ainda não fizemos nada com ela. Inclusive se você executar esse código não acontecerá nada. Veja aqui abaixo a criação de uma instância dessa classe (o chamado objeto) e a execução do método enviarTesteTecnico.

const candidaturaAda = new Candidatura('Ada Lovelace', 'Dev FullStack Coodesh', 5500);

candidaturaAda.enviarTesteTecnico();

Ao executar esse código você verá o seguinte resultado: [LOG]: “Enviar e-mail para Ada Lovelace”.

Veja que agora temos uma camada de abstração para a criação de candidaturas. Se uma pessoa desenvolvedora for desenvolver algo a partir de um objeto dessa classe não precisa se preocupar em saber qual o código dentro do método enviarTesteTecnico. Isso nada mais é que o conceito de abstração em orientação a objetos.

Encapsulamento

Esse é um conceito simples de aplicar, pois é simplesmente para mantermos as propriedades protegidas de acessos diretamente, produzindo dessa forma efeitos não desejados nas nossas classes. 

Do jeito que foi escrita nossa classe e por conta do TypeScript, as propriedades estão com acesso público, ou seja, agora é possível acessar essas propriedades dessa forma:

console.log(candidaturaAda.pessoaCandidata)

Veja que o nome da Ada foi escrito na tela, da mesma forma conseguimos reatribuir valor para essa propriedade. Para evitar esse comportamento devemos adicionar os modificadores de acessos tanto para as propriedades quanto para o método.

Veja o código a seguir:

class Candidatura {
    private _pessoaCandidata: string;
    private _vaga: string;
    private _pretensaoSalarial: number;

    // código do construtor omitido

    public enviarTesteTecnico(){
        console.log('Enviar email para ' + this._pessoaCandidata);
    }

    public get pessoaCandidata(){
        return this._pessoaCandidata;
    }

    public set pessoaCandidata(pessoaCandidata: string){
        this._pessoaCandidata = pessoaCandidata;
    }
}

Perceba que agora, além dos modificadores, adicionei também dois outros métodos especiais. O método get pessoaCandidata será o método para acessar o valor da propriedade pesssoaCandidata e o método set pessoaCandidata será utilizado para alterar o valor dessa propriedade. Ao executar o código abaixo novamente, o resultado pode parecer o mesmo mas de fato não é.

console.log(candidaturaAda.pessoaCandidata)

Dessa forma, fizemos o encapsulamento da nossa classe permitindo o acesso da propriedade pessoaCandidata apenas de forma indireta pelos métodos get e set dessa propriedade. 

Tente adicionar os getters e setters para as outras propriedades dessa classe. Ah, e se você não conhece que é Ada Lovelace vale uma pesquisa para conhecer um pouco da história da programação.

Espero que esse artigo o tenha ajudado a compreender sobre os conceitos de abstração e encapsulamento em orientação a objetos. Continue estudando para se preparar para as vagas aqui na Coodesh.

E aproveite para fazer parte da nossa comunidade e conferir as vagas mais recentes para DEVs. 

Escrito por Rodrigo Barreto

Formado em Física Computacional pela USP - São Carlos com pós-graduação em Desenvolvimento de Sistemas para Dispositivos Móveis pelo IFSP - São Carlos. Tem experiência em desenvolvimento web e mobile. Atualmente é desenvolvedor Full-stack na Coodesh.

Guia Para Contratar e Recrutar Desenvolvedor Sênior

Como contratar e recrutar Desenvolvedor Sênior

Carreira de desenvolvedor Mobile React Native: como ingressar?