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 は、規模拡大に耐えるために整理された進化です。