Один из способов взглянуть на сплоченность в терминах ОО - это если методы в классе используют какой-либо из частных атрибутов. Используя метрики, такие как LCOM4 (Отсутствие связных методов), как указано в этом ответе gnat в этом ответе , вы можете определить классы, которые могут быть реорганизованы. Причина, по которой вы хотите реорганизовать методы или классы, чтобы сделать их более связными, заключается в том, что это упрощает разработку кода для других пользователей . Доверьтесь мне; Большинство технических руководителей и программистов по обслуживанию будут любить вас, когда вы решите эти проблемы.
Вы можете использовать инструменты в процессе сборки, такие как Sonar, чтобы определить низкую сплоченность в базе кода. Есть несколько очень распространенных случаев, когда я могу вспомнить, где методы имеют низкую «сплоченность» :
Случай 1: метод вообще не связан с классом
Рассмотрим следующий пример:
public class Food {
private int _foodValue = 10;
public void Eat() {
_foodValue -= 1;
}
public void Replenish() {
_foodValue += 1;
}
public void Discharge() {
Console.WriteLine("Nnngghhh!");
}
}
Одному из методов Discharge()не хватает сплоченности, потому что он не касается ни одного из частных членов класса. В этом случае есть только один частный член: _foodValue. Если это ничего не делает с внутренностями класса, то действительно ли оно там? Метод может быть перемещен в другой класс, который может быть назван, например FoodDischarger.
// Non-cohesive function extracted to another class, which can
// be potentially reused in other contexts
public FoodDischarger {
public void Discharge() {
Console.WriteLine("Nnngghhh!");
}
}
Вы делаете это в Javascript, так как функции являются объектами первого класса, разгрузка может быть свободной функцией:
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
Случай 2: класс полезности
Это на самом деле распространенный случай, который нарушает сплоченность. Всем нравятся служебные классы, но они обычно указывают на недостатки проектирования и в большинстве случаев усложняют поддержку кодовой базы (из-за высокой зависимости, связанной с служебными классами). Рассмотрим следующие классы:
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;
}
}
Здесь мы видим, что служебный класс должен иметь доступ к свойству в классе Food. Методы в служебном классе в этом случае не имеют никакой сплоченности, потому что для выполнения этой работы нужны внешние ресурсы. В этом случае, не лучше ли иметь методы в классе, с которыми они работают сами по себе (как в первом случае)?
Случай 2b: Скрытые объекты в служебных классах
Есть еще один случай вспомогательных классов, где есть нереализованные доменные объекты. Первая реакция коленного рефлекса, которую программист имеет при программировании манипуляции со строками, - это написать для нее служебный класс. Как здесь, который проверяет пару общих строковых представлений:
public static class StringUtils {
public static bool ValidateZipCode(string zipcode) {
// validation logic
}
public static bool ValidatePhoneNumber(string phoneNumber) {
// validation logic
}
}
Здесь большинство не осознают, что почтовый индекс, номер телефона или любое другое представление строки могут быть самим объектом:
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
}
}
Идея о том, что вы не должны «обрабатывать строки» напрямую, подробно описана в этом посте @codemonkeyism , но тесно связана с связностью, потому что программисты используют строки, помещая логику в служебные классы.