Fundamentos da programação 10 min de leitura 13 mar 2026

Encapsulamento: O primeiro pilar da Programação Orientada a Objetos

Fala Dev, tudo em riba?

No artigo anterior nós entendemos o que é a Programação Orientada a Objetos (POO), como modelamos um objeto, compreendemos o que é um construtor, atributos, métodos e como instanciamos um objeto, resumindo, aprendemos o básico do básico. Caso não tenha lido o artigo anterior, recomendo fortemente a leitura.

Agora iremos abordar os pilares da POO. Esses pilares são o que fazem a POO brilhar e ser um paradigma da programação tão dinâmico. O primeiro pilar que iremos abordar é o Encapsulamento. Então bora para o conteúdo do artigo!

Modificadores

Antes de aprofundarmos no assunto do artigo, precisamos entender, primeiramente o que são os modificadores na POO.

Os modificadores determinam o nível de visibilidade de atributos e métodos de uma classe. São eles:

Antes de vermos exemplos de como os modificadores atuam, vamos entender o que é encapsulamento e conectar os conceitos.

O que é Encapsulamento?

Encapsulamento é um princípio que tem dois aspectos complementares: agrupar dados e comportamentos relacionados em uma única unidade (a classe), e esconder o estado interno dessa unidade, controlando como ele é acessado e modificado. Isso permite controlar e garantir que um objeto nunca entre em um estado inválido.

Pensa comigo: em um sistema de vendas, um pedido nunca deveria ter um status abacaxi (viajei no exemplo aqui). O status deve transitar entre pendenteconfirmadofaturadofinalizadocancelado….e por ai vai. Essa transição de status faz parte da regra de negócio do objeto e o encapsulamento é o mecanismo que garante que essas regras sejam respeitadas sempre, independentemente de quem estiver usando a classe.

Vamos a um exemplo:

class User {
  public name: string;
  private passwordHash: string; // ninguém de fora deve tocar nisso
  
  constructor(name: string, passwordHash: string) {
    this.name = name;
    this.passwordHash = passwordHash;
  }

  // O objeto expõe um método seguro, sem vazar o hash
  public checkPassword(input: string): boolean {
    // Em produção: compare hashes (ex: bcrypt.compare(input, this.passwordHash))
    // Aqui está simplificado para focar no conceito de encapsulamento
    return this.passwordHash === input;
  }
}

const user = new User("Carlos", "abc123hashed");

console.log(user.name);          // ✅ funciona
console.log(user.passwordHash);  // ❌ erro de compilação — é privado
user.checkPassword("abc123hashed"); // ✅ forma correta de interagir

Entendendo o código acima:

Após a criação do objeto, na linha console.log(user.name); acessamos diretamente o valor do atributo name. Não seria a forma ideal (e veremos isso mais adiante) mas funciona pois esse atributo está público (olha o modificador public na criação dele).

Já ao executar a linha console.log(user.passwordHash); vamos receber um erro, pois esse atributo é privado (passwordHash foi criado com modificador private) então não pode ser acessado diretamente, somente a própria classe tem acesso.

Por fim, na linha user.checkPassword("abc123hashed"); estamos chamando o método, o comportamento checkPassword e informando como parâmetro a senha abc123hashed. Note que a ideia desse método é verificar se a senha fornecida é a mesma senha presente no atributo privado passwordHash. O método está exposto publicamente, porém ele faz a verificação da senha recebida com a senha que foi definida na criação do objeto e que só pode ser acessada por métodos da própria classe. Isso é visível na linha return this.passwordHash === input; onde o termo this refere-se a acessar algo da própria classe.

Entendeu como o encapsulamento funcionou no código acima? Basicamente expôs o que poderia ser exposto e controlou o acesso a senha (passwordHash) por ser uma dado sensível.

Beleza, até aqui vimos como funciona os modificadores public e private, mas e o protected? Bom esse carinha eu vou deixar para demonstrar o funcionamento dele no próximo artigo, vai fazer mais sentido e você entenderá o motivo.

Getters e Setters

Conforme comentado acima, o ideal não seria acessar o valor de um atributo diretamente e também deve ser possível em algum momento alterar o valor de um atributo definido com o modificador private. No caso do exemplo anterior, deveria ser possível alterar a senha para uma nova, concorda?

Da mesma forma o objeto User pode ter um status que defina se ele está ativo ou não no sistema. Esse status não deve ter a possibilidade de modificação externa, pois faz parte de uma regra de negócio e deve ser garantido que ele deve transitar entre valores corretos. No entanto deve ser possível, de alguma forma, consultar qual é o status atual do usuário. Como alguém de fora lê o status do objeto User?

Para conseguirmos ler ou alterar o valor de um atributo privado de fora da classe, utilizamos os Getters e os Setters.

Acessando o valor de um atributo privado utilizando Getter

Vamos ver um código exemplo de como acessar o valor de um atributo que está privado para acesso externo à classe:

enum EUserStatus {
  Active = 'active',
  Inactive = 'inactive'
}

class User {
  public name: string;
  private passwordHash: string;
  private _status: EUserStatus; // convenção: _ para atributos privados com getter/setter

  constructor(name: string, passwordHash: string) {
    this.name = name;
    this.passwordHash = passwordHash;
    this._status = EUserStatus.Active;
  }

  get status(): EUserStatus {
    return this._status
  }

  // O objeto expõe um método seguro, sem vazar o hash
  public checkPassword(input: string): boolean {
    // Em produção: compare hashes (ex: bcrypt.compare(input, this.passwordHash))
    // Aqui está simplificado para focar no conceito de encapsulamento
    return this.passwordHash === input;
  }
}

const user = new User("Carlos", "abc123hashed");
console.log(user.status);  

Note que temos um atributo status que é privado, só é acessível pela própria classe. Quando um objeto do tipo User é criado, ele recebe no construtor o status active. Foi criado o getter get status(): e é esse carinha que expõe o valor do status, como pode ser visto na linha console.log(user.status);. Massa não acha?

Alterando o valor de um atributo privado utilizando Setter

Aproveitando o exemplo do status, vamos alterar o valor dele para inactive utilizando o setter:

enum EUserStatus {
  Active = 'active',
  Inactive = 'inactive'
}

class User {
  public name: string;
  private passwordHash: string;
  private _status: EUserStatus; // convenção: _ para atributos privados com getter/setter

  constructor(name: string, passwordHash: string) {
    this.name = name;
    this.passwordHash = passwordHash;
    this._status = EUserStatus.Active;
  }

  get status(): EUserStatus {
    return this._status
  }

  set status(value: EUserStatus) {
    this._status = value;
  }

  // O objeto expõe um método seguro, sem vazar o hash
  public checkPassword(input: string): boolean {
    // Em produção: compare hashes (ex: bcrypt.compare(input, this.passwordHash))
    // Aqui está simplificado para focar no conceito de encapsulamento
    return this.passwordHash === input;
  }
}

const user = new User("Carlos", "abc123hashed");

console.log(user.status);
user.status = EUserStatus.Inactive;
console.log(user.status);
user.status = 'pendente' as any; // ❌ erro de compilação — não é um EUserStatus válido

Note que agora adicionamos um setter para status. Isso pode ser visto na linha set status(value: EUserStatus). Perceba que o tipo do parâmetro é o próprio enum EUserStatus — isso é importante: ao invés de validar os valores permitidos manualmente com condicionais, deixamos o TypeScript fazer esse trabalho em tempo de compilação. Qualquer tentativa de atribuir um valor fora do enum, como 'pendente' ou 'abacaxi', gera um erro antes mesmo do código rodar.

Nas quatro últimas linhas do código, depois do objeto criado, é feito:

Conseguiu perceber a importância de proteger o valor do atributo status e a utilização do getter e do setter? Garantimos que sempre o valor do status será um valor correto.

Encapsulamento no contexto do backend

Em projetos backend, o encapsulamento aparece principalmente em dois lugares:

Conclusão

Entender o conceito de Encapsulamento é muito importante, pois sua correta aplicação trará benefícios como:

Espero que esse artigo tenha contribuído para seu aprendizado ou entendimento sobre o conceito de Encapsulamento, um dos 4 pilares da Programação Orientada a Objetos. No próximo artigo veremos o segundo pilar, a Herança.

Forte abraço e até mais!

#backend #encapsulamento #OOP #orientacao a objetos #POO #programaçao #typescript