Lucas Merencia

Getters e setters não são encapsulamento!

Sempre que se fala de encapsulamento nós desenvolvedores de software, ficamos presos a um conceito de que as classes devem ser encapsuladas para ocultar a informação e tudo mais, porém na grande maioria das vezes, ao menos para desenvolvedores Java, é criada uma classe com alguns atributos privados e são gerados getter e setters para todos eles. Fico pensando qual é o sentido de gerar estes getter e setters indiscriminadamente e a falsa sensação encapsulamento que temos.

Encapsulamento é muito mais do que ocultar a informação ou de esconder atributos de uma classe. O encapsulamento é um dos conceitos primários da modularização de software e nele deve-se ocultar as decisões de design suscetíveis a mudanças. Assim o encapsulamento pode ser diretamente ligado ao principio Open Closed, onde seus módulos podem (e provavelmente vão) sofrer alterações, porém seus clientes não precisarão ser modificados ou corrigidos por que algo foi alterado.

Sempre que criamos um método getter ou setter não é simplesmente por criar para dar acesso a atributos privados. A decisão de criar ou não deve sempre ser consciente, fazendo um paralelo com nosso dia a dia, quando usamos um microondas usamos o painel (interface) para informar o tempo que ele ficará ligado, em alguns casos selecionar a potência e pressionar o iniciar… Imagine agora se você tivesse além do painel do microondas a opção de aplicar um campo elétrico contínuo entre o ânodo e o cátodo. Basicamente é isso que estamos fazendo ao criar getters e setters para tudo sem avaliar se é necessário ou não. Estamos expondo “coisas” que não deveriam ser expostas, o microondas irá continuar funcionando e internamente irá aplicar o campo elétrico porém não precisamos saber disso, certo?

Ok, então como deveríamos fazer isso?

Imagine agora uma classe que representa um semáforo, teríamos algo assim:

public class Semaphore {
  private String state;

  public Semaphore() {
    this.state = "stop";
  }

  public void nextState() {
    if (state.equals( "clear" )) {
      state = "caution";
    } else if (state.equals( "stop" )) {
      state = "clear";
    } else {
      state = "stop";
    }
  }

  public String getState() {
    return state;
  }
}

No exemplo do semáforo podemos obter o estado atual dele e trocar o estado, porém as decisões de troca de estado não são uma responsabilidade do cliente que está usando o semáforo. Por isso foi exposto o status criando um getter para ele e expondo o comportamento de troca de estado, criando o método nextState.

Outra situação comum (ao menos para desenvolvedores Java) são classes criadas para representar objetos de negócio como os VOs e DTOs, nestes casos, como o propósito é apenas uma representação de um objeto em um determinado estado, ele deveria ser imutável e portanto não deve ter métodos setters, por exemplo, se fosse criado um VO para a classe Semaphore teríamos algo assim:

public class SemaphoreVO {
  public final String state;

  public SemaphoreVO(Semaphore semaphore) {
    state = semaphore.getState();
  }

  public String getState() {
    return state;
  }
}

Dito tudo isso, acho que devemos parar de banalizar os getters e setters e começar a pensar nos conceitos do encapsulamento, ao invés de sair gerando getters e setters para todos os atributos de todas as classes criadas. Gerar estes métodos para tudo não é encapsular, seria muito mais fácil deixar todos os atributos públicos, afinal, se tudo é exposto e se tudo pode ser alterado de todos os lugares não está encapsulado!