PrincípioIniciante5 min de leitura6 seções1967–1972, Data aproximada

Encapsulamento

Esconder o estado atrás de um contrato: quem usa o objeto não sabe — nem depende de — como ele guarda dados por dentro. Sem isso, cada mudança de representação vaza para quem consome; com isso, o objeto protege suas invariantes e pode mudar a implementação sem quebrar o resto.

Em 10 segundos

Encapsulamento é esconder o estado atrás de um contrato. Quem usa não depende de como o dado é guardado; o objeto protege suas regras. Sem isso, todo consumidor vira cúmplice da representação — e mudar o interno vira mudança em cascata.

Antes de ter nome

Information hiding de Parnas: o módulo deve ocultar decisões de projeto que possam mudar.

  • #principio
  • #oop
  • #contrato
  • #invariante
  • #abstracao
Analogia

O caixa eletrônico, não o cofre aberto

Você não mete a mão no cofre do banco: deposita, saca, consulta. O banco muda o layout do cofre sem te avisar. Encapsulamento é isso — operações públicas, estado fora do alcance. Abrir o campo saldo é deixar o cofre na rua.

01Conceito

Contrato, não paredes

O ponto não é ‘tornar private’. É decidir o que o resto do sistema pode assumir. Se o único método é setSaldo, você encapsulou o nome do campo e vazou a liberdade de corromper o valor.

Abstração caminha junto: o consumidor pensa em ‘depositar’, não em ‘somar no array de lançamentos’. Quando a implementação muda e o contrato aguenta, o encapsulamento pagou a conta.

Sem o padrão × com o padrão

Estado atrás do contrato

  • Campos privados / internos ao módulo
  • Operações que validam e preservam regras
  • Representação livre para evoluir

Um pouco mais de API — em troca de um objeto que ainda faz sentido daqui a um ano.

Encapsular é escolher o contrato; o ‘private’ é só o mecanismo.
Passo a passoDo vazamento ao contrato
  1. 1

    Esconder o estado

    Campos viram privados / internos ao módulo — o consumidor não escreve direto.

  2. 2

    Publicar operações

    Métodos com nomes de domínio (`depositar`, `pagar`) validam e preservam invariantes.

  3. 3

    Expor só o necessário

    Leitura via getter ou cópia; nunca a coleção mutável interna.

  4. 4

    Evoluir por dentro

    Com o contrato estável, a representação pode mudar sem quebrar quem consome.

02No mundo real

Como isso aparece na prática

Pedido com status público

Cenário

Um pedido.status = 'pago' aparecia em três services. Alguém setou 'cancelado' depois do pagamento sem estornar.

Como o padrão entra

O status virou transição por métodos (pagar, cancelar) que checam o estado atual antes de mudar.

Trade-off: Mais métodos no agregado. Em troca, transição ilegal deixa de ser possível por atribuição direta.

Config espalhada em objeto mutável

Cenário

Um singleton de config era mutado em testes e em runtime — um teste ‘consertava’ o valor e o próximo falhava.

Como o padrão entra

Config virou imutável na borda; mudanças passam por rebuild ou por um serviço com API explícita.

Trade-off: Menos atalho nos testes. Em troca, o estado global parou de vazar entre casos.

03Cuidado

Onde isto dá errado

  1. Getter/setter que só espelha o campo

    Se setX aceita qualquer valor e getX devolve o campo, você não encapsulou — só mudou a sintaxe do vazamento.

  2. Expor a coleção interna

    getItens() que devolve a lista mutável interna permite pedido.getItens().clear() por trás das costas do objeto.

  3. Encapsular demais e virar god object

    Esconder estado não autoriza um único objeto a saber de tudo. SRP continua valendo — encapsule por responsabilidade, não por tamanho.

O jeito errado

Compila, roda, passa no code review. E quebra depois.

Campo público (ou getter que devolve a lista interna) e a invariante espalhada em quem usa.

class Pedido {
  status: "rascunho" | "pago" | "cancelado" = "rascunho";
  itens: string[] = [];
}
// Em qualquer lugar do sistema:
pedido.status = "pago";
pedido.itens.push("x"); // ou .clear() — sem regra

O que quebra

  • alguém seta status ilegalo domínio aceita estados que o negócio não existe
  • a lista interna vazamutação silenciosa sem passar pelo agregado

A saída: Transições por método (pagar, adicionarItem) e coleções expostas só como cópia ou leitura.

05Implementação

Do campo público ao contrato

// SEM encapsulamento: o estado é público e qualquer um mexe.
class ContaRuim {
  saldo = 0;
}
const c = new ContaRuim();
c.saldo = -999; // ninguém impede — invariante morta

// COM encapsulamento: o estado mora atrás de um contrato.
class Conta {
  #saldo = 0;
  depositar(v: number) {
    if (v <= 0) throw new Error("valor inválido");
    this.#saldo += v;
  }
  get saldo() { return this.#saldo; } // lê, não escreve à vontade
}
// Quem usa Conta não sabe — nem precisa saber — como o saldo é guardado.
06Decisão

Quando usar × quando evitar

Use quando

3
  • Há invariante a proteger.
  • A representação interna pode mudar.
  • Fronteira de módulo: API pública × detalhe privado.

Evite quando

2
  • DTO sem regra — o formato já é o contrato.
  • Getter/setter 1:1 sem validação (teatro de encapsulamento).

Testar o que ficou

3 armadilhas de Encapsulamento viram perguntas, com o nome do padrão escondido, misturadas com padrões parecidos.

Onde isto aparece de verdade

Você já usa isto, talvez sem saber o nome.

  • campos private / #privadoA linguagem força o acesso pelo método — o estado deixa de ser propriedade pública do chamador.
  • getters sem setter cegoLer o saldo é ok; escrever à vontade não. O contrato decide o que pode mudar e como.
  • módulo ES que não exportaO que não sai do arquivo é interno: o importador só vê a API exportada — encapsulamento de módulo.

O padrão em uma linha

Sem nome de domínio, sem cerimônia. Só a ideia.

class Conta { #saldo = 0; depositar(v: number) { this.#saldo += v; } }

O que ele cobra

1 salto a mais entre a chamada e o efeito.

  • Mais métodos (e nomes) do que expor o campo direto
  • Contrato mal desenhado vira getter/setter que só empacota o vazamento

Não vale se: o dado é realmente um DTO sem invariante — aí um record/objeto plano é o contrato, não um teatro de private.

Onde isto aparece

Continue por aqui