オブジェクト指向入門 第13回 情報隠蔽
今回は、プログラムを分割してモジュール化する際の方針/基準である、情報隠蔽(Informaton hidding)について書いてみたいと思います。
情報隠蔽はオブジェクト指向に限定されない一般的なモジュール分割基準ですが、情報という言葉が曖昧なためかカプセル化と混同されることもあるようです。
情報隠蔽に関する有名な論文に、D.L.Parnas の "On the Criteria To Be Used in Decomposing Systems into Modules"(1972年)がありますが、そこには何を隠すかについて、
"We propose instead that one begins with a list of difficult design decisions or design decisions which are likely to change. Each module is then designed to hide such a decision from the others."
と書かれています。
つまり、そのモジュールに関する決定事項を他のモジュールから隠すということです。
以前に作成したパックマンのプログラムを、再び例にしたいと思います。
あの時は、最初にモンスターをクラスにした際に、赤モンスターを次のように書きました。
class RedMonster : IMonster
{
void IMonster.Move()
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("追いかけます。");
Console.ResetColor();
}
}
しかし、これは他の色のモンスタークラスとコードが重複する個所が多かったので、それを無くすために基本クラスを追加して、モンスタークラス間で重複するコードを基本クラスに移しました。
その結果、赤モンスタークラスは、以下のようになりました。
class RedMonster : Monster
{
protected override ConsoleColor GetSkinColor()
{
return ConsoleColor.Red;
}
protected override string GetAlgorithm()
{
return "追いかけます。";
}
}
この「クラス間で重複するコードを基本クラスに移す」が、決定になります。
これは難しい決定ではないですが、これにより赤モンスタークラスは丸ごと書き換わっています。
変更前と変更後を行単位で比較しますと、中カッコ以外の行は全て変更があります。
モジュールレベルでは大変更となる決定をしたわけですが、モンスタークラスを使用する呼び出し側のモジュールは一行も変更がありませんでした。
これが、決定事項を他のモジュールから隠すということです。
開発者レベルでは、クラスを変更した際は、その事を呼び出し側モジュールの担当者へ連絡するでしょう。
作業レベルでも、変更箇所の動作確認を呼び出し側モジュールを結合した状態で行うことは、普通にあるでしょう。
しかしモジュールレベルでは、この決定が完全に隠されていて、変更が変更を呼ぶといった変更の連鎖が発生していないのです。
アルゴリズム変更の決定なども、情報隠蔽の対象となります。例えば、売上履歴を検索する検索モジュールと、検索結果を並び替えるソートモジュールがあるとします。
この時、ソートモジュールのパフォーマンスが向上するようにアルゴリズムを変更したとしても、検索モジュールに変更が発生しないようにソートモジュールの引数などを設計します。
また、検索精度が向上するように検索モジュールのアルゴリズムを変更したとしても、ソートモジュールに変更が発生しないように検索結果のデータ構造を設計をします。
しかし、モジュール分割はコーティング前にする作業ですが、変更の決定はコーティング後にも発生する事があります。
このジレンマを解消するのに、オブジェクト指向が役立ちます。
カプセル化やインターフェイスは、クラスの内部構造や実装方法を隠蔽するのに役立ちます。
ポリモーフィズムを上手に使えば、新しいモジュールを追加しても、その決定を隠蔽したまま他のモジュールに追加モジュールを使わせる事ができます。
外部的振る舞いを保ったまま内部構造を改善するリファクタリングは、正に情報隠蔽のテクニック集です。
情報隠蔽を意識しながらクラス設計をすると、オブジェクト指向の様々な知識を効果的に使えるでしょう。
■まとめ
・情報隠蔽を意識して、オブジェクト指向を使いこなす。
■ご参考
・デイビッド・パーナス
"On the Criteria To Be Used in Decomposing Systems into Modules"
次回に続きます。
情報隠蔽はオブジェクト指向に限定されない一般的なモジュール分割基準ですが、情報という言葉が曖昧なためかカプセル化と混同されることもあるようです。
情報隠蔽に関する有名な論文に、D.L.Parnas の "On the Criteria To Be Used in Decomposing Systems into Modules"(1972年)がありますが、そこには何を隠すかについて、
"We propose instead that one begins with a list of difficult design decisions or design decisions which are likely to change. Each module is then designed to hide such a decision from the others."
と書かれています。
つまり、そのモジュールに関する決定事項を他のモジュールから隠すということです。
以前に作成したパックマンのプログラムを、再び例にしたいと思います。
あの時は、最初にモンスターをクラスにした際に、赤モンスターを次のように書きました。
class RedMonster : IMonster
{
void IMonster.Move()
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("追いかけます。");
Console.ResetColor();
}
}
しかし、これは他の色のモンスタークラスとコードが重複する個所が多かったので、それを無くすために基本クラスを追加して、モンスタークラス間で重複するコードを基本クラスに移しました。
その結果、赤モンスタークラスは、以下のようになりました。
class RedMonster : Monster
{
protected override ConsoleColor GetSkinColor()
{
return ConsoleColor.Red;
}
protected override string GetAlgorithm()
{
return "追いかけます。";
}
}
この「クラス間で重複するコードを基本クラスに移す」が、決定になります。
これは難しい決定ではないですが、これにより赤モンスタークラスは丸ごと書き換わっています。
変更前と変更後を行単位で比較しますと、中カッコ以外の行は全て変更があります。
モジュールレベルでは大変更となる決定をしたわけですが、モンスタークラスを使用する呼び出し側のモジュールは一行も変更がありませんでした。
これが、決定事項を他のモジュールから隠すということです。
開発者レベルでは、クラスを変更した際は、その事を呼び出し側モジュールの担当者へ連絡するでしょう。
作業レベルでも、変更箇所の動作確認を呼び出し側モジュールを結合した状態で行うことは、普通にあるでしょう。
しかしモジュールレベルでは、この決定が完全に隠されていて、変更が変更を呼ぶといった変更の連鎖が発生していないのです。
アルゴリズム変更の決定なども、情報隠蔽の対象となります。例えば、売上履歴を検索する検索モジュールと、検索結果を並び替えるソートモジュールがあるとします。
この時、ソートモジュールのパフォーマンスが向上するようにアルゴリズムを変更したとしても、検索モジュールに変更が発生しないようにソートモジュールの引数などを設計します。
また、検索精度が向上するように検索モジュールのアルゴリズムを変更したとしても、ソートモジュールに変更が発生しないように検索結果のデータ構造を設計をします。
しかし、モジュール分割はコーティング前にする作業ですが、変更の決定はコーティング後にも発生する事があります。
このジレンマを解消するのに、オブジェクト指向が役立ちます。
カプセル化やインターフェイスは、クラスの内部構造や実装方法を隠蔽するのに役立ちます。
ポリモーフィズムを上手に使えば、新しいモジュールを追加しても、その決定を隠蔽したまま他のモジュールに追加モジュールを使わせる事ができます。
外部的振る舞いを保ったまま内部構造を改善するリファクタリングは、正に情報隠蔽のテクニック集です。
情報隠蔽を意識しながらクラス設計をすると、オブジェクト指向の様々な知識を効果的に使えるでしょう。
■まとめ
・情報隠蔽を意識して、オブジェクト指向を使いこなす。
■ご参考
・デイビッド・パーナス
"On the Criteria To Be Used in Decomposing Systems into Modules"
次回に続きます。