Encapsulamento em POO: Aprenda a Aplicar do Jeito Certo

Cada paradigma de programação possui seus pilares fundamentais. No caso da programação orientada a objetos (POO), os principais são: herança, polimorfismo, abstração e encapsulamento e aqui vou trazer alguns elementos relacionado a encapsulamento.

Variáveis: Atributos

Na maioria das linguagens de programação baseadas no paradigma da orientação a objetos, é comum modelar classes com atributos privados (private) ou protegidos (protected) para restringir o acesso direto. No entanto, um erro frequente é tornar os atributos privados e, ao mesmo tempo, fornecer getters e setters para todos eles. Essa prática enfraquece o encapsulamento, pois, na prática, não há grande diferença entre acessar um atributo diretamente ou por meio de métodos simples.

É importante destacar que a visibilidade dos modificadores de acesso varia entre linguagens. No Java, por exemplo, um membro com protected pode ser acessado por classes do mesmo pacote (package-private) e por subclasses, independentemente do pacote. Já no Kotlin, protected limita o acesso apenas às subclasses, impedindo que outras classes do mesmo pacote o acessem diretamente.

Portanto, ao modelar classes, é essencial compreender as particularidades da linguagem escolhida para garantir um encapsulamento eficiente e coerente com a arquitetura do sistema.

Métodos: Comportamentos

Adicionar métodos a um objeto vai além de simplesmente obter ou modificar valores de atributos. Mas aí você pode estar pensando: Entendi, mas como vou inicializar meu objeto?

Existem algumas formas de fazer isso, e a mais comum é o uso do construtor. Mas talvez você diga: Manoel, nem sempre tenho todas as informações no momento da criação do objeto. Vou precisar passar null para os atributos que ainda não tiverem valores?

A resposta rápida é: não necessariamente. Você pode, por exemplo, criar múltiplos construtores (vamos aprofundar melhor isso ao falar de polimorfismo). Outra abordagem bastante utilizada é o padrão de projeto Builder, um dos padrões do GoF (Gang of Four), que, particularmente, gosto bastante de aplicar.

O verdadeiro propósito do encapsulamento vai além de simplesmente criar métodos para alterar valores e esconder variáveis. Seu objetivo é prover comportamentos que modifiquem o estado do objeto de forma controlada. Isso é especialmente crítico em domínios complexos, onde a modelagem correta do comportamento do objeto impacta diretamente a integridade e a consistência do sistema.


Encapsulamento e Modelagem de Comportamentos

Como a POO busca simular o mundo real por meio de objetos, vejamos um exemplo:

Imagine uma classe Pessoa, que possui um estado representado pelos atributos energia e percentual de gordura. Se a energia da pessoa está baixa, como podemos alterá-la? Bastaria chamar setEnergia(100)?

No mundo real, isso não faz sentido. Em vez disso, estimulamos uma ação: comer. O método comer(Alimento alimento) encapsula essa ação. O que acontece dentro dele não precisa ser conhecido por quem o chama, mas sabemos que, ao final, a energia do objeto Pessoa será ajustada.

Encapsulamento na Prática

A energia de uma pessoa é um estado do corpo, enquanto comer é um comportamento. O encapsulamento garante que a energia não possa ser diretamente alterada. Em vez disso, apenas os métodos apropriados podem modificar esse estado de maneira controlada.

Além disso, essa ação pode desencadear outros efeitos. Se a pessoa consumir mais energia do que gasta, o excesso será armazenado como gordura. No entanto, o atributo percentual de gordura não pode ser modificado diretamente. Ao comer, percebemos que a energia excedente aumenta o percentual de gordura. E para reduzi-lo? É necessário adotar outro comportamento, como correr, por exemplo.

Ou seja, o corpo possui métodos que representam ações e atributos que representam estados. A modificação dos estados ocorre internamente, como consequência das ações, e não por manipulação direta dos atributos.

A exposição deliberada dos atributos para modificação direta compromete o encapsulamento, tornando o sistema mais frágil e propenso a inconsistências.


A Importância do Encapsulamento no Design de Código

Quando ignoramos o poder do encapsulamento, dois problemas comuns surgem:

1️⃣ Primitive Obsession (Obsessão por Tipos Primitivos): Ocorre quando negligenciamos a essência de um atributo e, em vez de encapsulá-lo em um objeto mais representativo, utilizamos diretamente tipos primitivos. Isso pode resultar em um código menos expressivo e mais difícil de manter. Esse é um tema relevante que explorarei em um artigo futuro.

2️⃣ Entidades Anêmicas: Ocorre quando classes atuam apenas como recipientes de dados, contendo apenas getters e setters, sem comportamento real. No Domain-Driven Design (DDD), esse tipo de modelagem enfraquece o domínio, pois desloca a lógica de negócio para serviços externos, tornando o código menos expressivo e mais difícil de evoluir.

Um bom design de código aproveita ao máximo os recursos da linguagem. Na programação orientada a objetos, isso significa aplicar o encapsulamento corretamente, limitando o acesso direto aos atributos e criando entidades ricas em comportamento.

O DDD vai além, pois incentiva a criação de modelos que refletem fielmente o domínio do mundo real. Ao utilizar uma linguagem ubíqua, alinhada com especialistas do negócio, garantimos que o código represente com precisão os conceitos e regras essenciais do sistema. Assim, as entidades deixam de ser apenas estruturas de dados e passam a capturar o significado e a intenção do domínio.

Modelar classes de forma adequada não só assegura a integridade das regras de negócio, mas também torna o sistema mais expressivo, coeso e sustentável a longo prazo.


Conclusão

O encapsulamento vai muito além de simplesmente tornar atributos privados. Seu verdadeiro poder está na criação de comportamentos que garantem a consistência do domínio.

Ao aplicar encapsulamento corretamente e modelar entidades ricas, garantimos que nosso código não apenas funcione, mas represente fielmente as regras e conceitos do mundo real. Isso fortalece o design do sistema, melhora sua manutenção e reduz erros decorrentes de modificações inconsistentes no estado dos objetos.

Se gostou desse conteúdo, fique atento ao próximo artigo, onde explorarei mais sobre

No responses yet

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Latest Comments

Nenhum comentário para mostrar.