Esse capítulo provavelmente vai se unir à SOLID ou interpolar diversos assuntos lá tratados.

Mudanças em Cascata, Menos pontos de contato

Encapsulamento é um princípio fundamental da programação orientada a objetos (POO) que ajuda a controlar o acesso e a modificação de dados dentro de uma classe. Ele se refere à prática de esconder os detalhes de implementação de uma classe de códigos externos e expor apenas uma interface pública para interagir com a classe. Isso pode ajudar a evitar mudanças em cascata em um sistema de software limitando o número de pontos de contato entre diferentes partes do código.

Uma maneira de alcançar o encapsulamento (pelo menos em uma linguagem OO) é usando modificadores de acesso como "private" ou "protected" em campos e métodos de classe. Isso pode evitar que códigos externos acessem ou modifiquem diretamente o estado interno da classe e forçar o uso de métodos ou propriedades públicas que fornecem uma forma controlada de interagir com a classe.

Essa não é a única maneira e nem todos os atributos de uma classe devem ter cegamente getters e setters, faz sentido uma pessoa depois de sua criação ter seu id alterado? Esse setter tem que existir, realmente? Outra ocasião importante que indica falta de encapsulamento é comentada no ponto 1 do capítulo de 3. Refatoração → Casos Usuais.

class MyClass {
    private int data;

    public int getData() {
        return data;
    }

    public void setData(int newData) {
        data = newData;
    }
}

O encapsulamento também pode ser usado para evitar mudanças em cascata mantendo o número de pontos de contato entre diferentes partes do código o mínimo possível. Ou seja, ao invés de termos em 5 lugares diferentes o código Float.parseFloat(getData()) poderíamos encapsular isso dentro de um método na classe Data se isso for uma regra de Data ou um comportamento relacionado à ela (mesmo que não seja, provavelmente é um comportamento de alguma outra classe). Depois dessa refatoração, ao mexermos nesse método, cuidaremos dos 5 pontos que o utilizam, ao invés de ficar buscando por ai a linha de Float.parseFloat(getData()) e quebrarmos o código pois não encontramos uma ocorrência.

Devo abstrair um determinado parâmetro/retorno?

Já dissemos muito sobre abstrações e encapsulamento, mas quando você deve abstrair um certo parâmetro ou retorno? Aquele atributo String CPF na sua classe é realmente prejudicial? Se sim, vale a pena criar uma classe para defini-lo?

Suponha que você precise criar um objeto Usuário, que tem como parâmetro do construtor um nome e senha.

class Usuario{
	...
	public Usuario (String nome, String senha){}
}
Usuario user1 = new Usuario("kaue", "123456");

Nesse caso, como você pode garantir que usuário deve receber sua senha como plain text, e não depois de passar por um hash? Ou que a senha deve ter ao menos 6 caracteres, isso foge da lógica e semântica estabelecida pela tipo String, apesar disso, não é uma validação que dá muito trabalho, um simples length já resolveria o problema do tamanho, nesse caso, não acho que valeria criar uma classe somente para isso, mas quanto ao problema do hash, como validaríamos que o cliente usou corretamente o construtor e passou uma senha como plain text?

É simples, somente ver a implementação da classe Usuário, mas se isso não está claro, temos ai um code smell, uma espécie de acoplamento mental. Se você não tivesse acesso à Usuário, não teria como adivinhar. Nesse caso em específico, mudar o nome da variável para plainText seria uma solução caso.

Contudo, se a solução não for tão simples, acredito que normalmente passa a valer a pena criar uma classe de domínio para o parâmetro (ou retorno). Uma classe Senha com um construtor privado e métodos factory seria uma alternativa.

Untitled

Trazendo isso para um exemplo real, durante o handling de metadatas as guardávamos como Map<String,Object> , repetidos em diversos lugares, apesar disso, usávamos o Map em seu exato contexto, sem a necessidade de métodos a mais além dos próprios do Map e o seu contexto e significado era exatamente o que um map representava, nesse caso, não sentimos necessidade de abstrair o tipo.

Protegendo Fronteiras