安定度・抽象度等価の原則(SAP)とは?
安定度・抽象度等価の原則(SAP: Stable Abstractions Principle) は、「安定した(変更されにくい)コンポーネントほど、抽象度も高くあるべき」 というソフトウェア設計の原則です。
簡単に言うと
- 変更しにくい(=安定した)コンポーネントは、抽象的(=インターフェースや抽象クラス)であるべき。
- 逆に、頻繁に変更されるコンポーネントは、具体的な実装(=詳細なクラスやビジネスロジック)であるべき。
これを守ることで、変更しやすく、柔軟性の高いシステム を作ることができます。
SAPが生まれた背景
ソフトウェア開発では、次のような問題がよく発生します:
頻繁に変更される具体的なコードに多くのコンポーネントが依存している
- 例えば、データベース接続の詳細を含むモジュールに他の多くのコンポーネントが依存している場合、データベースの仕様変更が起きると、システム全体に影響が出てしまいます。
安定したコンポーネントが具体的すぎる
- 例えば、基本的なログ出力処理(めったに変更しない機能)が、特定のライブラリに強く依存している場合、別のログ出力方法に変更するのが難しくなります。
これらの問題を防ぐため、「安定したコンポーネントは抽象的に、頻繁に変更されるコンポーネントは具体的に」 というSAPが提唱されました。
抽象度の継続

SAPを適用するには、抽象度を適切に設計すること が重要です。
- 高い抽象度(例:インターフェース、抽象クラス)
- 変更されにくい
- さまざまな実装に対応可能
- 他のコンポーネントからの依存が多い
- 低い抽象度(例:具体的なクラスや関数)
- 変更されやすい
- 特定の機能を実装
- 他のコンポーネントからの依存が少ない
良い設計の例
- 「安定しているが変更しにくい部分」(例:システム全体の基本ルール) → インターフェースや抽象クラス にする。
- 「頻繁に変わる部分」(例:UIのデザインや特定のライブラリの選定) → 具象クラス(具体的な実装) にする。
主系列(Main Sequence)とは?
SAPを図で表すと、「安定度」と「抽象度」の関係を示す主系列(Main Sequence) という直線が出てきます。
主系列の基本概念
- X軸(安定度 I):
- 0(左側):変更されやすい(依存されていない)コンポーネント
- 1(右側):変更されにくい(多くのコンポーネントから依存されている)コンポーネント
- Y軸(抽象度 A):
- 0(下側):具体的な実装(クラス、関数など)
- 1(上側):抽象的な概念(インターフェース、抽象クラス)
主系列の直線 は、「安定したコンポーネントほど抽象的であるべき」 というSAPの原則を示します。
除外すべきゾーン(回避すべきエリア)
SAPを適用する上で、避けるべき設計パターン が2つあります。
「不安定な抽象」ゾーン(左上)
- 抽象度が高いのに、安定していないコンポーネント
- 例:頻繁に変更されるインターフェースや抽象クラス
悪い例
Java
// 頻繁に変更される抽象クラス(本来は変更されにくいべき)
abstract class UIFramework {
abstract void render();
}
問題点
- UIの仕様は頻繁に変更されるのに、抽象クラスとして定義されているため、変更のたびにすべての実装クラスに影響を及ぼす。
「具体的な安定」ゾーン(右下)
- 具体的なのに安定しているコンポーネント
- 例:システムの基盤に特定のライブラリを強く依存させる
悪い例
Java
// ログ機能を特定のライブラリに強く依存
class Logger {
public void log(String message) {
System.out.println("Logging: " + message); // これが変更しにくい
}
}
問題点
Logger
は多くのコンポーネントから依存されるが、具体的すぎるため、変更が困難になる。
主系列からの距離(D値)
D値(Distance from Main Sequence) は、コンポーネントが主系列からどれくらい離れているかを示す指標です。
計算式
Java
D = |A + I - 1|
- D = 0 に近い → 良い設計(主系列上)
- D が大きい → 変更に弱い設計(不安定な抽象、具体的な安定)
具体的な良い設計の例
Java
// 変更されにくい(安定した)抽象クラス
interface Database {
void connect();
}
// 変更されやすい(不安定な)具体クラス
class MySQLDatabase implements Database {
public void connect() {
System.out.println("Connecting to MySQL...");
}
}
なぜ良いのか?
- Database インターフェースは変更されにくい → 安定している
- 具体的な MySQLDatabase は変更されやすい → 変更がしやすい
D値が0に近く、主系列上にあるため、良い設計となる!
まとめ
SAPのポイント
- 安定したコンポーネントほど抽象的であるべき
- 頻繁に変更される部分は、具体的な実装にすべき
- 主系列を意識して設計し、D値を小さくする
- 「不安定な抽象」「具体的な安定」のゾーンを避ける
SAPを意識すると
- 変更しやすく、拡張しやすいシステム が作れる!
- 不安定な変更が広がるのを防げる
- 長期的に保守しやすいコード になる
コメント