こんにちは、キャスレーコンサルティング SI(システム・インテグレーション)部の清水(誠)です。

今回は、シンプルかつメンテナンス性の高いコードを書くために重要な概念のひとつである
「モジュール結合度」について取り上げます。

そういえば情報処理試験を受けた時に覚えはしたけど、実務ではあまり意識する機会がなかったなあ……
という方もいらっしゃるのではないでしょうか。

他ならぬ筆者がそうだったので、今回改めておさらいし、具体例と合わせてご紹介してみようと思います。
今後の実務で活用していただたくきっかけとなれば幸いです。

なお、ここで言うモジュールとは関数や変数を一定の単位でまとめたものを指し、
一般的なオブジェクト指向型言語での「クラス」に置き換えていただいても差し支えありません。
また、サンプルコードはC#にて記述します。

モジュール結合度とは?

モジュール結合度とは、モジュール同士の密接さを表す尺度です。
6段階に分類され、結合度が低いほど独立性が高くなり、良いモジュールとされています。
以下、結合度の高い順にご説明します。

1.内容結合

あるモジュールが、別のモジュールの外部宣言していない内部状態を直接参照したり、
命令の一部を共有したりしている状態を指します。
内容結合では、一方のモジュールの変更が他方のモジュールに影響を及ぼすので
障害につながる確率が高くなります。

アセンブラ等の低水準言語では陥りがちですが、高水準言語では一般的には発生しないためサンプルコードは省略します。

2.共通結合

共通域に定義したデータをいくつかのモジュールが直接使用するような状態を指します。
共通域の定義データとはいわゆるグローバル変数、JavaやC#で言うところのstatic変数です。

・共通域のデータは他のモジュールで書き換えられてしまう可能性がある
・共通域のデータ定義の変更がそれを使用しているモジュール全てに影響する

等、デメリットが多くあります。

サンプルコード

using System;

public class CommonParameter
{
    // 共通域のデータ
    public static string Name;
    public static int Number;
    public static string Place;
}

public class CommonCoupling {
    public string GetMessage(){
        var message = CommonParameter.Name + "が" + CommonParameter.Number + "匹います。";
        return message;
        // CommonParameter.Placeは使用しない
    }
}

public class TestCommon
{
    public static void Main() {
        CommonParameter.Name = "犬";
        CommonParameter.Number = 2;
        CommonParameter.Place = "庭";
        var data = new CommonCoupling();
        Console.WriteLine(data.GetMessage());
    }
}

実行結果
 犬が2匹います。

3.外部結合

外部宣言したデータ(= public static変数)を共有している状態を指します。
データを共有するという点では共通結合と似ていますが、必要なデータのみを外部宣言するため
共通結合よりも結合度は弱くなります。

サンプルコード

using System;

public class ExternalCoupling {

    // 必要なパラメータをstatic化
    public static string Name;
    public static int Number;

    public string GetMessage(){
        var message = Name + "が" + Number + "匹います。";
        return message;
    }
}

public class TestExternal
{
    public static void Main() {
        ExternalCoupling.Name = "猫";
        ExternalCoupling.Number = 3;
        var ext = new ExternalCoupling();
        Console.WriteLine(ext.GetMessage());
    }
}

実行結果
 猫が3匹います。

4.制御結合

呼び出し側のモジュールが、呼び出されるモジュールの制御を指示するデータ(いわゆるフラグ)を
パラメータとして渡す状態を指します。呼び出し側は相手のモジュールのロジックを知っている必要があるため、
相手をブラックボックス扱いできず結合度が強くなります。

サンプルコード

using System;

public class ControlCoupling {
    public string GetMessage(string name, int number, string type){
        string message = string.Empty;

        // 引数typeによって処理を分岐
        if (type == "哺乳類")
        {
            message = name + "が" + number + "匹います。";
        }
        else if (type == "鳥類"){
            message = name + "が" + number + "羽います。";
        }
        return message;
    }
}

public class TestControl
{
    public static void Main() {
        var ctrl = new ControlCoupling();
        Console.WriteLine(ctrl.GetMessage("ハムスター", 4, "哺乳類"));
        Console.WriteLine(ctrl.GetMessage("ハト", 5, "鳥類"));
    }
}

実行結果
 ハムスターが4匹います。
 ハトが5羽います。

5.スタンプ結合

共通域にないデータ構造を、2つのモジュール間で受け渡す状態を指します。
結合度は比較的弱いですが、スタンプ結合の場合は受け渡すデータ構造の一部を使用しないことがあります。

サンプルコード

using System;

public class StampCoupling {
    public string GetMessage(StampParameter p){
        var message = p.Name + "が" + p.Number + "匹います。";
        return message;
        // p.Placeは使用しない
    }
}
public class StampParameter
{
    // 受け渡し用データ(インスタンス変数なので共通域ではない)
    public string Name;
    public int Number;
    public string Place;

}

public class TestStamp
{
    public static void Main() {
        var p = new StampParameter() ;
        p.Name = "アリ";
        p.Number = 6;
        p.Place = "地中";
        var stmp = new StampCoupling();
        Console.WriteLine(stmp.GetMessage(p));
    }
}

実行結果
 アリが6匹います。

6.データ結合

単純なデータだけをパラメータとして受け渡す状態を指します。
相手モジュールをブラックボックス化できるので、結合度は一番弱くなります。

サンプルコード

using System;

public class DataCoupling {
    public string GetMessage(string name, int number){
        var message = name + "が" + number + "匹います。";
        return message;
    }
}

public class TestData
{
    public static void Main() {
        var data = new DataCoupling();
        Console.WriteLine(data.GetMessage("コツメカワウソ", 7));
    }
}

実行結果
 コツメカワウソが7匹います。

おわりに

一般的に、モジュール同士の結合度が低いほどコードの可読性・再利用性が高まり、
障害が発生した場合も対応がしやすくなります。

プロダクト毎のアーキテクチャやコーディング規約の許す範囲で、
可能な限り結合度を弱く保つコーディングを心掛けましょう。

最後までお読みいただきありがとうございました。