KISS・YAGNI・DRY や SOLID など、多くの設計原則が目指す最終的な評価軸は 結合度(coupling)を下げ、凝集度(cohesion)を上げることに集約される。これは Larry Constantine らが 構造化設計の文脈で提唱した概念で、オブジェクト指向以前から通用する、モジュール分割の普遍的な基準になっている。
結合度(Coupling)¶
モジュール間の依存の強さ。結合度が高いほど、一方の変更がもう一方に波及しやすくなる。代表的な分類を、弱い(望ましい) 順に挙げる。
| 種類 | 説明 |
|---|---|
| データ結合(Data Coupling) | 必要なデータだけを引数として渡す。最も弱い=望ましい結合 |
| スタンプ結合(Stamp Coupling) | データ構造やオブジェクトをまるごと渡すが、一部のフィールドしか使わない |
| 制御結合(Control Coupling) | 呼び出し先の内部の分岐を制御するフラグを渡す(do_something(mode="A") など) |
| 外部結合(External Coupling) | 特定の外部フォーマット・プロトコル・デバイスに依存する |
| 共通結合(Common Coupling) | グローバル変数やグローバルな可変状態を複数モジュールが共有する |
| 内容結合(Content Coupling) | あるモジュールが別モジュールの内部実装(プライベートな状態)に直接触れる。最も強い=避けるべき結合 |
# 制御結合の例:呼び出し側が内部の分岐を知っている必要がある
def send_notification(user, mode):
if mode == "email":
send_email(user)
elif mode == "sms":
send_sms(user)
# データ結合に近い例:役割ごとにインターフェースを分け、必要なデータだけを渡す
class EmailNotifier:
def notify(self, user): send_email(user)
class SmsNotifier:
def notify(self, user): send_sms(user)SOLIDのDIP や 依存性注入 は、具象クラスへの依存を 抽象への依存に置き換えることで結合度を下げる典型的な手段。
凝集度(Cohesion)¶
モジュール内部の要素同士がどれだけ強く関連しているか。凝集度が高いほど、モジュールは「1つのことに集中している」状態になる。 強い(望ましい)順に挙げる。
| 種類 | 説明 |
|---|---|
| 機能的凝集(Functional Cohesion) | すべての要素が単一の明確な目的のために協調する。最も強い=望ましい凝集 |
| 逐次的凝集(Sequential Cohesion) | ある処理の出力が次の処理の入力になるよう順序立てて構成されている |
| 通信的凝集(Communicational Cohesion) | 同じデータを扱う処理がまとまっている |
| 手続き的凝集(Procedural Cohesion) | 実行される順序でまとまっているだけで、データの関連は薄い |
| 時間的凝集(Temporal Cohesion) | 「初期化処理」のように、実行タイミングが同じというだけでまとまっている |
| 論理的凝集(Logical Cohesion) | 似たカテゴリというだけでまとめられ、内部でフラグ分岐して切り替える |
| 偶発的凝集(Coincidental Cohesion) | 関連のない処理がたまたま同じモジュールに置かれている。最も弱い=避けるべき凝集 |
SRP(単一責任の原則) は「クラスの凝集度を機能的凝集に近づけよ」という主張とほぼ同義であり、 SLAP も抽象レベルを揃えることで手続き的凝集に陥るのを防ぐ原則と解釈できる。
まとめ¶
理想は「モジュール内は強く凝集し、モジュール間は疎に結合する」状態。個々の原則やデザインパターンで迷ったときは、 「この変更は結合度を下げるか、凝集度を上げるか」を判断基準にすると一貫した意思決定がしやすい。