Princípio: Favorecemos coesão através do encapsulamento
O Encapsulamento é basicamente o ato de juntar comportamentos e estados que fazem sentido no mesmo lugar, garantindo maior coesão ao código, é um conceito básico que precisa ser dominado. Veja esse código em um repositório de um framework da Apache
for (Address address : vcard.getAddresses()) {
boolean workAddress = false;
for (AddressType addressType : address.getTypes()) {
if (AddressType.PREF.equals(addressType) || AddressType.WORK.equals(addressType)) {
workAddress = true;
break;
}
}
if (!workAddress) continue;
Sem entender muito do código e de seu contexto, já somos capaz de refatorar isso de uma maneira melhor, poderíamos simplesmente usar:
if(!adress.hasWorkAdress()) continue;
Com isso, o código escrito na classe ficaria mais legível e a função de descobrir se há endereço de trabalho ou não, passa a ser da classe Adress
e pode ser replicado sem problemas através de toda a aplicação. Se decidirmos mudar a regra de negócio no estado atual, teríamos que verificar por esse imenso código esparramado por todo o programa, o que não acontece no código refatorado.
Apenas com essa alteração:
Como podemos detectar isso? Um forte indicativo que algo está estranho é estarmos usando um estado interno e aplicando lógica em cima desse estado interno fora de sua classe.
Métodos privados também podem indicar esse tipo de comportamento, talvez até mesmo a necessidade do nascimento de novas entidades.
private Person createUserAccount(String username, Collection<GrantedAuthority> authorities,PersonAttributesLookup personAttributesLookup) {
Person person = null;
if (hasAccountCreationPermission(authorities)) {
person = new Person();
person.setEnabled(true);
person.setUsername(username);
try {
// Get the Person Attributes to create the person
final PersonAttributesResult attr =
personAttributesLookup.lookupPersonAttributes(username);
person.setSchoolId(attr.getSchoolId());
person.setFirstName(attr.getFirstName());
person.setLastName(attr.getLastName());
person.setPrimaryEmailAddress(attr.getPrimaryEmailAddress());
ensureRequiredFieldsForDirectoryPerson(person);
person = create(person);
externalPersonService.updatePersonFromExternalPerson(person, false);
LOGGER.info("Successfully Created Account for {}", username);
} catch (final ObjectNotFoundException onfe) {
...
}
Refatorando:
person.setSchoolId(attr.getSchoolId());
person.setFirstName(attr.getFirstName());
person.setLastName(attr.getLastName());
person.setPrimaryEmailAddress(attr.getPrimaryEmailAddress());
// passa a se tornar
public Class Person{
...
Person setAttributesBasedOnAttributesResult(PersonAttributesResult attr){
this.person.setSchoolId(attr.getSchoolId());
this.person.setFirstName(attr.getFirstName());
this.person.setLastName(attr.getLastName());
this.person.setPrimaryEmailAddress(attr.getPrimaryEmailAddress());
}
}
// seria usado:
person.setAttributesBasedOnAttributesResult(attr);
Somente nessa alteração, já travamos setters que podem não ser interessantes para o negócio (como alterar o schoolId sem alterar o emailAdress, se isso for uma regra existente), ou seja, o código antigo estava desprotegido e acoplado mentalmente à alguma regra externa, precisamos sempre que atualizarmos o primeiro nome atualizar também o segundo? não sei. Se sim, podemos fazer com que o encapsulamento garanta isso.