OOの観点から凝集度を調べる1つの方法は、クラスのメソッドがプライベート属性のいずれかを使用している場合です。この回答で gnatが指摘したように、LCOM4(Cohesive Methodsの欠如)などのメトリックを使用します。、リファクタリングできるクラスを特定できます。メソッドまたはクラスをよりまとまりのあるものにリファクタリングする理由は、他の人がそれを使用するためのコード設計を簡単にするためです。私を信じて; これらの問題を解決するとき、ほとんどの技術リーダーと保守プログラマーはあなたを愛しています。
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!");
}
}
メソッドの1つであるにDischarge()
は、クラスのプライベートメンバーのいずれにも触れないため、凝集性がありません。この場合、プライベートメンバーは1人のみです_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によって詳しく説明されていますが、ユーティリティクラスにロジックを入れて文字列を使用する方法のため、結束と密接に関連しています。