私は最近ソフトウェア開発会社にインターンとして入社した学生です。大学に戻ったとき、私の教授の1人が、「低結合と高凝集度」を達成するために努力する必要があると言っていました。
低結合の意味を理解しています。これは、ある場所での変更が別の場所でのコードを壊さないように、別々のコンポーネントのコードを別々に保持することを意味します。
しかし、高い凝集度とはどういう意味ですか。同じコンポーネントのさまざまな部分を互いにうまく統合することを意味する場合、それがどのように有利になるのか理解できません。
高い凝集度とはどういう意味ですか?その利点を理解するために例を説明できますか?
コメント
- の重複の可能性があります結束と結合の測定基準?
- ウィキペディアの記事はあなたの質問に十分に答えていませんか? en.wikipedia.org/wiki/Cohesion_(computer_science)
- これに関する優れた記事があります: msdn.microsoft.com/en-us/magazine/cc947917.aspx
- @EoinCarroll:残念ながら、現時点でのウィキペディアの記事は何の役にも立ちません新しいプログラマーが使用できる具体的な例。理論は優れていますが、'低凝集度を取り巻く間違いを犯すまで、'実際には固執しません。高い凝集度は、なぜそれが重要なのか、そしてそれを達成するための方法を完全に理解するためにプログラミングに数年かかったトピックの1つです。
- 私は読むまで、凝集度を本当に理解していませんでした。クリーンコード。あなたもそうすべきです。
回答
OOの観点から凝集性を見る1つの方法は、クラスはいずれかのプライベート属性を使用しています。 この回答でgnatが指摘しているように、LCOM4(Lack of 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()
は、クラスのプライベートメンバーのいずれにも触れないため、まとまりがありません。この場合、プライベートメンバーは_foodValue
の1つだけです。クラスの内部で何もしない場合、それは本当にそこに属しているのでしょうか?メソッドは、eg 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 で詳しく説明されています。ただし、プログラマーがユーティリティクラスにロジックを配置して文字列を使用する方法は、結束と密接に関連しています。
コメント
- これで、ORMを取得できればカスタムのZipCodeクラスとPhoneNumberクラスを適切に処理するには:|
- +1の良い例。最後のポイントについては、 sourcemaking.com/refactoring/primitive-obsession
- @Peteも参照してください。変換を提供すると、ORMが処理します。文字列から定義されたタイプ(ZipCode、PhoneNumber)への演算子: msdn.microsoft.com/en-us/library/85w54y0a.aspx
回答
高い凝集度とは、コンテンツや機能を共有するパーツを結合または融合するために、類似した関連するものをまとめることを意味します。理由または目標。言い換えると、凝集度が低いということは、たとえば、「要点」ではなく、複数の目的に役立つ関数/クラス/コードエンティティを意味する可能性があります。 実行するアイデアの1つは、 1つのことを実行し、それをうまく実行することです。他には、多くの場所で同様の機能を複製しないという明らかな事実が含まれる可能性があります。これにより、コードベースの局所性も改善され、特定の場所(ファイル、クラス、セット)で特定の種類のものが見つかります。
例として、2つまたは3つの目的を果たすクラスを考えてみましょう。リソース(ファイルなど)をロード/保存してから、分析して表示します。このようなクラスは、まったく関係のない2つの個別のタスク(ファイルI / O、分析、表示)を少なくとも管理するため、まとまりが低い。凝集度の高い設計では、リソースの読み込みと保存、分析、表示に個別のクラスを使用できます。
一方、低結合度は、個別のものを分離して相互作用させることを目的としています。可能な限り少なくすることで、複雑さが軽減され、設計が簡素化されます。
回答
これは、オブジェクトの各部分がオブジェクトの機能と密接に関連していることを意味します。これは、機能または責任の観点から、オブジェクト内に無駄がほとんどまたはまったくないことを意味します。これにより、問題のオブジェクトが何に使用されるのかについての理解を深めることができます。
コメント
- doesn 'オブジェクトだけでなく、より高いレベルにも適用されますか?たとえば、タスクに関連するオブジェクト/関数を名前空間にグループ化しますか?