Eine Möglichkeit, die Kohäsion in Bezug auf OO zu betrachten, besteht darin, dass die Methoden in der Klasse eines der privaten Attribute verwenden. Mithilfe von Metriken wie LCOM4 (Mangel an kohäsiven Methoden), auf die gnat in dieser Antwort hingewiesen hat , können Sie Klassen identifizieren, die umgestaltet werden könnten. Der Grund, warum Sie Methoden oder Klassen umgestalten möchten, um eine größere Kohäsion zu erzielen, besteht darin, dass das Code-Design für andere einfacher zu verwenden ist . Vertrau mir; Die meisten Techniker und Wartungsprogrammierer werden Sie lieben, wenn Sie diese Probleme beheben.
Sie können in Ihrem Erstellungsprozess Tools wie Sonar verwenden , um eine geringe Kohäsion in der Codebasis zu identifizieren. Es gibt ein paar sehr häufig Fälle , dass ich mir vorstellen kann , wo Methoden sind niedrig in „Kohäsionskraft“ :
Fall 1: Die Methode ist überhaupt nicht mit der Klasse verbunden
Betrachten Sie das folgende Beispiel:
public class Food {
private int _foodValue = 10;
public void Eat() {
_foodValue -= 1;
}
public void Replenish() {
_foodValue += 1;
}
public void Discharge() {
Console.WriteLine("Nnngghhh!");
}
}
Einer der Methoden Discharge()fehlt der Zusammenhalt, da sie keines der privaten Mitglieder der Klasse berührt. In diesem Fall gibt es nur ein privates Mitglied: _foodValue. Wenn es mit den Interna nichts zu tun hat, gehört es dann wirklich dorthin? Die Methode könnte in eine andere Klasse verschoben werden, die zB benannt werden könnte FoodDischarger.
// Non-cohesive function extracted to another class, which can
// be potentially reused in other contexts
public FoodDischarger {
public void Discharge() {
Console.WriteLine("Nnngghhh!");
}
}
Wenn Sie dies in Javascript tun, kann die Entladung eine freie Funktion sein, da Funktionen erstklassige Objekte sind:
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
Fall 2: Gebrauchsklasse
Dies ist tatsächlich ein häufiger Fall, der den Zusammenhalt bricht. Jeder liebt Utility-Klassen, aber diese weisen normalerweise auf Designfehler hin und machen die Pflege der Codebasis in den meisten Fällen schwieriger (aufgrund der hohen Abhängigkeit, die mit Utility-Klassen verbunden ist). Betrachten Sie die folgenden Klassen:
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;
}
}
Hier sehen wir, dass die Utility-Klasse auf eine Eigenschaft in der Klasse zugreifen muss Food. Die Methoden in der Utility-Klasse haben in diesem Fall überhaupt keine Kohäsion, da sie für ihre Arbeit externe Ressourcen benötigen. Wäre es in diesem Fall nicht besser, die Methoden in der Klasse zu haben, mit der sie arbeiten (ähnlich wie im ersten Fall)?
Fall 2b: Versteckte Objekte in Dienstprogrammklassen
Es gibt einen anderen Fall von Dienstprogrammklassen, in denen nicht realisierte Domänenobjekte vorhanden sind. Die erste Reaktion eines Programmierers beim Programmieren der String-Manipulation besteht darin, eine Utility-Klasse dafür zu schreiben. Wie die hier, die einige gebräuchliche Zeichenfolgendarstellungen überprüft:
public static class StringUtils {
public static bool ValidateZipCode(string zipcode) {
// validation logic
}
public static bool ValidatePhoneNumber(string phoneNumber) {
// validation logic
}
}
Was die meisten hier nicht erkennen, ist, dass eine Postleitzahl, eine Telefonnummer oder eine andere Zeichenfolgenrepräsentation selbst ein Objekt sein kann:
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
}
}
Die Idee, dass Sie nicht direkt mit Strings umgehen sollten, wird in diesem Blogpost von @codemonkeyism detailliert beschrieben , hängt jedoch eng mit der Kohäsion zusammen, da die Art und Weise, wie Programmierer Strings verwenden, indem Logik in Utility-Klassen eingefügt wird.