Uma maneira de observar a coesão em termos de OO é se os métodos da classe estão usando algum dos atributos privados. Usando métricas como LCOM4 (Falta de Métodos Coesivos), conforme apontado pelo gnat nesta resposta aqui , você pode identificar classes que podem ser refatoradas. A razão pela qual você deseja refatorar métodos ou classes para ser mais coesa é que isso torna o design do código mais simples para outras pessoas o usarem . Confie em mim; a maioria dos líderes técnicos e programadores de manutenção o amarão quando você corrigir esses problemas.
Você pode usar ferramentas em seu processo de criação, como o Sonar, para identificar baixa coesão na base de código. Há alguns casos muito comuns em que posso pensar em que os métodos são baixos em "coesão" :
Caso 1: O método não está relacionado à classe
Considere o seguinte exemplo:
public class Food {
private int _foodValue = 10;
public void Eat() {
_foodValue -= 1;
}
public void Replenish() {
_foodValue += 1;
}
public void Discharge() {
Console.WriteLine("Nnngghhh!");
}
}
Um dos métodos, Discharge()
carece de coesão porque não toca em nenhum membro privado da classe. Neste caso há apenas um membro particular: _foodValue
. Se ele não faz nada com os internos da turma, então realmente pertence a ele? O método pode ser movido para outra classe que poderia ser nomeada, por exemplo FoodDischarger
.
// Non-cohesive function extracted to another class, which can
// be potentially reused in other contexts
public FoodDischarger {
public void Discharge() {
Console.WriteLine("Nnngghhh!");
}
}
Ao fazer isso em Javascript, como as funções são objetos de primeira classe, a descarga pode ser uma função gratuita:
function Food() {
this._foodValue = 10;
}
Food.prototype.eat = function() {
this._foodValue -= 1;
};
Food.prototype.replenish = function() {
this._foodValue += 1;
};
// This
Food.prototype.discharge = function() {
console.log('Nnngghhh!');
};
// can easily be refactored to:
var discharge = function() {
console.log('Nnngghhh!');
};
// making it easily reusable without creating a class
Caso 2: Classe de Utilidade
Este é realmente um caso comum que quebra a coesão. Todo mundo adora classes de utilidade, mas elas geralmente indicam falhas de design e, na maioria das vezes, dificulta a manutenção da base de código (devido à alta dependência associada às classes de utilidade). Considere as seguintes classes:
public class Food {
public int FoodValue { get; set; }
}
public static class FoodHelper {
public static void EatFood(Food food) {
food.FoodValue -= 1;
}
public static void ReplenishFood(Food food) {
food.FoodValue += 1;
}
}
Aqui podemos ver que a classe de utilitário precisa acessar uma propriedade na classe Food
. Os métodos na classe de utilitário não têm coesão neste caso, porque precisam de recursos externos para fazer seu trabalho. Nesse caso, não seria melhor ter os métodos na classe em que eles estão trabalhando (como no primeiro caso)?
Caso 2b: objetos ocultos em classes de utilitário
Há outro caso de classes de utilitário em que existem objetos de domínio não realizados. A primeira reação instintiva que um programador tem ao programar a manipulação de strings é escrever uma classe de utilidade para ele. Como o que aqui valida algumas representações comuns de strings:
public static class StringUtils {
public static bool ValidateZipCode(string zipcode) {
// validation logic
}
public static bool ValidatePhoneNumber(string phoneNumber) {
// validation logic
}
}
O que a maioria não percebe aqui é que um código postal, um número de telefone ou qualquer outra representação de cadeia de caracteres pode ser um objeto em si:
public class ZipCode {
private string _zipCode;
public bool Validates() {
// validation logic for _zipCode
}
}
public class PhoneNumber {
private string _phoneNumber;
public bool Validates() {
// validation logic for _phoneNumber
}
}
A noção de que você não deve "manipular strings" diretamente é detalhada neste post do blog por @codemonkeyism , mas está intimamente relacionada à coesão porque a maneira como os programadores usam as strings colocando lógica nas classes de utilidade.