旧仕様への依存
説明(どんな問題か)
どんな状態か?
- 新しいコードから、既存の(古い)インターフェースを直接呼び出している
- API 仕様の違いを、呼び出し側で都度調整しており、ロジックが煩雑
- 「形式が違うけど、動かさなきゃ」と無理やり接続している
なぜ問題か?
- 呼び出し側が変換・調整処理を持ってしまい、責任が曖昧に
- API や仕様が変更されたとき、複数箇所に影響が波及
- 外部依存のテストや切り替えが難しくなる
アンチパターンのコード例
- TypeScript
- PHP
- Python
// レガシーAPI(旧仕様)
class LegacyPrinter {
printText(text: string) {
console.log(`*** ${text} ***`);
}
}
// 新しいコード
class ReportGenerator {
printSummary(text: string) {
const printer = new LegacyPrinter(); // ← 直接依存(インターフェース不一致)
// 無理やり旧APIに合わせる
const legacyFormat = text.toUpperCase();
printer.printText(legacyFormat); // ← ハードコーディング
}
}
<?php
// レガシーAPI(旧仕様)
class LegacyPrinter {
public function printText(string $text): void {
echo "*** {$text} ***\n";
}
}
// 新しいコード(無理やり接続)
class ReportGenerator {
public function printSummary(string $text): void {
$printer = new LegacyPrinter(); // ← 古いクラスを直接使っている
$legacyFormat = strtoupper($text); // ← 無理やり仕様に合わせる
$printer->printText($legacyFormat); // ← ハードコーディング
}
}
// 利用例
$report = new ReportGenerator();
$report->printSummary("月次レポート");
# レガシーAPI(旧仕様)
class LegacyPrinter:
def print_text(self, text: str):
print(f"*** {text} ***")
# 新しいコード(無理やり接続)
class ReportGenerator:
def print_summary(self, text: str):
printer = LegacyPrinter() # ← 直接依存
legacy_format = text.upper() # ← 無理やり仕様に合わせる
printer.print_text(legacy_format) # ← 古いインターフェースにベタ依存
# 利用例
report = ReportGenerator()
report.print_summary("月次レポート")
問題点:
- ReportGenerator が LegacyPrinter の具体的なメソッド名やフォーマットに依存
- インターフェースの違いを吸収せず、新旧の設計思想が混在している
- 大文字化などの処理が、文脈や責任を無視して ReportGenerator に書かれてしまっている(SRP 違反)
- 他の出力手段(新しい Printer クラスや外部 API)への切り替えができない
- テスト用のモックプリンターに置き換えることができない
- LegacyPrinter に依存する処理が増えると、同じような変換処理が至る所に出現
- 仕様変更時にすべての利用箇所に影響が波及する
パターン別のリファクタリング
対応可能なデザインパターン例
パターン | 概要 | 主な解決アプローチ |
---|---|---|
Adapter | インターフェースの整合性を取るための「橋渡し役」 | 新旧 API をつなぐ変換レイヤーを追加 |
Facade | サブシステムの複雑さを隠し、使いやすい窓口を提供 | 呼び出しを単純化したいときに使用 |
Proxy | オブジェクトへのアクセスを代理する | アクセス制御・キャッシュ・遅延実行などに有効 |