DI 登場以前の開発
DI が普及する前は、クラス内部で依存オブジェクトを直接 new する実装が一般的でした。受注システムのように機能が増えると、変更が連鎖しやすくなります。
昔の一般的スタイル
class OrderService {
private final ProductGateway productGateway = new ProductDbGateway();
private final DiscountRule discountRule = new CampaignDiscountRule();
private final NotifySender notifySender = new MailSender();
void createOrder(Order order) {
Product product = productGateway.findByCode(order.getProductCode());
int price = discountRule.apply(product, order.getQty());
notifySender.send(order.getCustomerMail(), \"受注完了\");
}
}
このコードは直感的ですが、「通知をメールから Slack に変更」「割引ロジック変更」などが起きるたびに
OrderService 自体の修正が必要になります。
問題1: 密結合(Tight Coupling)
利用側クラスが具体クラスを知りすぎる状態です。 依存先の変更が、利用側の変更に直結します。
問題2: テストが重い
本来は Service だけをテストしたいのに、実 DB / 実ファイル保存に繋がってしまう問題が起きます。 モック差し替えが難しいため、テスト速度と安定性が落ちます。
問題3: 変更コストが増える
| 変更要求 | DIなしで起きがちな影響 |
|---|---|
| 商品取得元を DB から外部APIに変更 | new ProductDbGateway() を書いた箇所を全修正 |
| 通知方式をメールからチャットに変更 | 受注処理クラスに直接手を入れる必要がある |
| 受注ロジックだけ単体テストしたい | 商品DBや通知処理を避けるための改修が先に必要 |
昔の実装が「間違い」なのではなく、当時は小規模・短期開発では妥当でした。DI は、規模拡大に耐えるために整理された進化です。