分岐ロジックの肥大化
説明(どんな問題か)
どんな状態か?
if
/else if
/switch
による条件分岐が多すぎてコードが読みにくい- 処理の追加・変更のたびに、同じ分岐ロジックを複数箇所に書く
- 条件が増えると、バグの温床になりやすく、保守性も低下
なぜ問題か?
- 修正時に全ての条件を確認する必要がある
- 1 つの関数・クラスに責任が集中する
- ユニットテストが困難(条件によって異なる処理が密結合)
- 拡張がしにくい(開閉原則に反する)
アンチパターンのコード例
- TypeScript
- PHP
- Python
function calculatePrice(userType: string, basePrice: number): number {
if (userType === "student") {
return basePrice * 0.8;
} else if (userType === "member") {
return basePrice * 0.9;
} else if (userType === "vip") {
return basePrice * 0.7;
} else {
return basePrice;
}
}
<?php
function calculatePrice(string $userType, float $basePrice): float {
if ($userType === "student") {
return $basePrice * 0.8;
} elseif ($userType === "member") {
return $basePrice * 0.9;
} elseif ($userType === "vip") {
return $basePrice * 0.7;
} else {
return $basePrice;
}
}
// 利用例
echo calculatePrice("student", 1000) . PHP_EOL; // 800
def calculate_price(user_type: str, base_price: float) -> float:
if user_type == "student":
return base_price * 0.8
elif user_type == "member":
return base_price * 0.9
elif user_type == "vip":
return base_price * 0.7
else:
return base_price
# 利用例
print(calculate_price("student", 1000)) # 800
問題点:
if/else
が増え続けると、可読性・テスト性・エラー発生リスクが高まる- 新しい
userType
を追加するたびに関数本体を修正する必要があり、安全に拡張できない - 割引の計算が直接埋め込まれていて、他の場所で使い回しにくく、一元管理が困難
パターン別のリファクタリング
対応可能なデザインパターン例
パターン | 概要 | 主な解決アプローチ |
---|---|---|
Strategy | 条件に応じた処理を外部に切り出す | 実行時に処理を差し替える柔軟性 |
State | 状態と処理を 1 対 1 で対応 | 条件を「状態オブジェクト」に任せる |
Command | 条件ごとの命令をオブジェクト化 | 実行・取り消しなど操作の記録にも ◎ |
Chain of Responsibility | 条件判定を責任の連鎖で処理 | 条件分岐をフローで自然に表現できる |
Interpreter | 文法に従ったルールや式を解釈・評価 | 複雑な条件ロジックを構文として分離し、拡張可能にする |