私はコンピュータープログラミングを学んでいて、いくつかの場所で結束の概念に出くわしました。ソフトウェアが「高い結束」を持つことが望ましいことは理解していますが、それはどういう意味ですか? 私は Java、C、および Python のプログラマーで、C++ Primer という本から C++ を学んでいます。この本では、まとまりについて言及されていますが、索引には含まれていません。このトピックに関するリンクをいくつか教えていただけますか? ウィキペディアのコンピュータ サイエンスの結束に関するページは、定性的な尺度であり、実際のコード例を示していないため、参考になりませんでした。
10 に答える
高い凝集度とは、明確に定義された仕事をするクラスがある場合です。凝集度が低いとは、クラスが多くの共通点のない多くの仕事をする場合です。
この例を見てみましょう:
2つの数値を加算するクラスがありますが、同じクラスが結果を表示するウィンドウを作成します。ウィンドウと追加操作にはあまり共通点がないため、これはまとまりの少ないクラスです。ウィンドウはプログラムの視覚的な部分であり、追加機能はその背後にあるロジックです。
凝集性の高いソリューションを作成するには、クラスWindowとクラスSumを作成する必要があります。ウィンドウはSumのメソッドを呼び出して結果を取得し、表示します。このようにして、アプリケーションのロジックとGUIを別々に開発します。
Steve McConnell のCode Completeからの説明:
凝集度とは、クラス内のすべてのルーチンまたはルーチン内のすべてのコードが中心的な目的をどれだけ密接にサポートしているかを示します。強く関連する機能を含むクラスは、 強力な結束を持っていると表現されます。ヒューリスティックな目標は、結束を可能な限り強くすることです。Cohesion は、複雑さを管理するための便利なツールです。これは、クラス内のコードが中心的な目的をサポートするほど、コードが行うすべてのことを脳がより簡単に記憶できるようになるためです。
Uncle Bob's Clean Codeからそれを達成するいくつかの方法:
クラスには少数のインスタンス変数が必要です。クラスの各メソッドは、これらの変数の 1 つ以上を操作する必要があります。一般に、メソッドが操作する変数が多いほど、そのメソッドはそのクラスに対してよりまとまりがあります。各変数が各メソッドによって使用されるクラスは、最大限にまとまりがあります。
一般に、このような最大限にまとまりのあるクラスを作成することはお勧めできませんし、可能でもありません。一方で、結束力を高くしたいと考えています。凝集度が高いということは、クラスのメソッドと変数が相互に依存し、論理的な全体としてぶら下がっていることを意味します。
結束の概念は結合の概念と強く関連しています。また、Single Responsibility Principle (SOLID の S) と呼ばれる、高い結束のヒューリスティックに基づく原則があります。
高凝集度は、ソフトウェアエンジニアリングの概念です。基本的に、それはクラスがそれがすることになっていることだけをするべきであると言い、そしてそれを完全に行います。想定されていない関数でオーバーロードしないでください。また、それに直接関連するものは、他のクラスのコードにも表示されないようにする必要があります。
スケールも考慮する必要があるため、例は非常に主観的です。単純なプログラムはモジュール化されすぎないようにする必要があります。そうしないと、断片化されてしまいます。一方、複雑なプログラムでは、複雑さを処理するために、より多くのレベルの抽象化が必要になる場合があります。
例:Eメールクラス。cc、bcc、subject、bodyへのデータメンバーが含まれている必要があり、これらのメソッドsaveAsDraft()、send()、discardDraft()が含まれている場合があります。ただし、login()はここにあるべきではありません。これは、多数の電子メールプロトコルがあり、個別に実装する必要があるためです。
凝集度は通常、LCOM (Lack of cohesion) メトリックの 1 つを使用して測定されます。元の LCOM メトリックは、Chidamber と Kemerer から来ました。例を参照してください: http://www.computing.dcu.ie/~renaat/ca421/LCOM.html
より具体的な例: クラスに、たとえば 1 つのプライベート フィールドと 3 つのメソッドがある場合。3 つのメソッドすべてがこのフィールドを使用して操作を実行する場合、クラスは非常にまとまりがあります。
まとまりのあるクラスの擬似コード:
class FooBar {
private SomeObject _bla = new SomeObject();
public void FirstMethod() {
_bla.FirstCall();
}
public void SecondMethod() {
_bla.SecondCall();
}
public void ThirdMethod() {
_bla.ThirdCall();
}
}
たとえば、クラスに 3 つのプライベート フィールドと 3 つのメソッドがあるとします。3 つのメソッドすべてが 3 つのフィールドの 1 つだけを使用する場合、クラスの凝集性は低くなります。
凝集度の低いクラスの疑似コード:
class FooBar {
private SomeObject _bla = new SomeObject();
private SomeObject _foo = new SomeObject();
private SomeObject _bar = new SomeObject();
public void FirstMethod() {
_bla.Call();
}
public void SecondMethod() {
_foo.Call();
}
public void ThirdMethod() {
_bar.Call();
}
}
1 つのことを行うクラスの原則は、Robert C. Martin に由来する単一責任原則であり、 SOLID原則の 1 つです。この原則では、クラスが変更される理由は 1 つだけであるべきであると規定しています。
単一責任の原則に近づくことで、よりまとまりのあるコードになる可能性がありますが、私の意見では、これらは 2 つの異なるものです。
これは、低凝集度の例です。
class Calculator
{
public static void main(String args[])
{
//calculating sum here
result = a + b;
//calculating difference here
result = a - b;
//same for multiplication and division
}
}
しかし、高い凝集度は、クラス内の関数が(名前が付けられているように)本来の機能を実行することを意味します。そして、他の機能の仕事をしている機能ではありません。したがって、以下は高凝集度の例です。
class Calculator
{
public static void main(String args[])
{
Calculator myObj = new Calculator();
System.out.println(myObj.SumOfTwoNumbers(5,7));
}
public int SumOfTwoNumbers(int a, int b)
{
return (a+b);
}
//similarly for other operations
}
結合という用語は、もともとソース コードのモジュールを、モジュールのソース コードが互いにどの程度関連しているかを示す定性的な尺度として説明するために使用されていました。結束の考え方は、さまざまな分野で使用されています。たとえば、軍事部隊などの集団は結束力があり、部隊内の人々が共通の目標に向かって協力することを意味します。
ソース コードの結束の本質は、モジュール内のソース コードが、明確に定義された共通の目標に向かって連携することです。モジュール出力を作成するために必要な最小限のソース コードはモジュール内にあり、それ以上はありません。インターフェイスは明確に定義されており、入力はインターフェイスを介して流入し、出力はインターフェイスを介して流出します。副作用はなく、ミニマリズムに重点が置かれています。
機能的にまとまったモジュールの利点は、単体テストの開発と自動化が簡単であることです。実際、モジュールの結束の良い尺度は、モジュールの徹底的な単体テストの完全なセットを作成することがいかに簡単かです。
モジュールは、オブジェクト指向言語のクラス、または関数型言語または C などの非オブジェクト指向言語の関数である場合があります。凝集度を測定するこの分野での元の作業の多くは、IBM での COBOL プログラムの作業に関係していました。 1970 年代なので、結束は間違いなく単なるオブジェクト指向の概念ではありません。
結束の概念と関連する結合の概念が生まれた研究の本来の意図は、理解しやすく、維持し、拡張しやすいプログラムの特徴がどこにあるのかを研究することでした。目標は、プログラミングのベスト プラクティスを学び、それらのベスト プラクティスを体系化し、そのプラクティスを他のプログラマーに教えることができるようにすることでした。
優れたプログラマーの目標は、環境と解決しようとしている問題を考慮して、可能な限りまとまりのあるソース コードを作成することです。これは、大規模なアプリケーションでは、ソース コード本体の一部の部分が、そのモジュールまたはクラス内のソース コードの結合レベルに関して他の部分と異なることを意味します。解決しようとしている問題のために、得られる最善の方法が時間的または連続的な結束である場合があります。
結束の最良のレベルは機能的結束です。機能的結合を備えたモジュールは、一連の入力を提供して特定の出力を取得するという点で、数学関数に似ています。真に機能するモジュールには、出力に加えて副作用がなく、いかなる種類の状態も維持されません。代わりに、モジュールの内部を公開することなくモジュールの機能をカプセル化する明確に定義されたインターフェースを持ち、モジュールを使用する人は特定の入力セットを提供し、特定の出力を返します。真に機能するモジュールは、スレッド セーフでもある必要があります。
多くのプログラミング言語ライブラリには、クラス、テンプレート、関数などの機能モジュールの例が多数含まれています。最も機能的なまとまりのある例は、sin、cosine、平方根などの数学関数です。
他の関数には、副作用があったり、ある種の状態が維持されたりして、それらの関数の使用がより複雑になる場合があります。
たとえば、例外をスローするか、グローバル エラー変数を設定する関数 ( errno
C の場合)、またはシーケンスで使用する必要がある関数 (strtok()
関数は、内部状態を維持するため、標準 C ライブラリの例です)、またはポインターを提供する必要があります。管理することや、何らかのログ ユーティリティにログを発行することはすべて、もはや機能的な結束ではない機能の例です。
私はユアドンとコンスタンティンのオリジナルの本である構造化プログラミングの両方を読みました.1980年代に私が最初に凝集のアイデアに出くわした場所であり、メイリル・ページ・ジョーンズの本構造化システム設計の実用的なガイドであり、ページ・ジョーンズは説明のはるかに優れた仕事をしました.カップリングと結束の両方。ユアドンとコンスタンティンの本は、もう少しアカデミックなようです。Steve McConnell の著書 Code Complete は非常に優れており、実用的であり、改訂版には優れたプログラミング プラクティスについて多くのことが書かれています。
まとまりとは、クラスまたはメソッドが定義された 1 つのジョブだけを実行することを意味します。メソッドまたはクラスの名前も自明でなければなりません。たとえば、電卓を作成する場合は、クラス名を「asdfghj」ではなく「calculator」にする必要があります。また、subtract() add() など、タスクごとにメソッドを作成することも検討する必要があります。将来あなたのプログラムを使用する可能性のあるプログラマーは、メソッドが何を行っているかを正確に知っています。適切な名前を付けると、コメントの労力を減らすことができます
また、原則は DRY です - 繰り返さないでください
この場合、 MSDN の記事はおそらくウィキペディアよりも有益です。