配線を1箇所変える例

ここでは「interface で十分では?」に対して、実装切替時の差を受注と商品の例で具体的に示します。

なぜ interface だけでは足りないのか

interface は「型の約束」を作りますが、 「どの実装を使うかをどこで決めるか」までは決めません。 そのため、実装選択が各クラスに散らばると、変更時に修正箇所が増えます。

interface だけの例

受注処理と在庫確認で同じ interface を使っていても、実装生成が分散しているケースです。

interface ProductGateway {
  Product findByCode(String code);
}

class OrderService {
  private final ProductGateway gateway = new ProductDbGateway();
}

class StockService {
  private final ProductGateway gateway = new ProductDbGateway();
}

この状態で「商品情報を外部APIから取得」に変更すると、 new ProductDbGateway() を書いた場所を探して直す必要があります。

DIで配線を集約した例

利用側は interface を受け取るだけにし、実装選択を設定クラスへ集約します。

class OrderService {
  private final ProductGateway gateway;
  OrderService(ProductGateway gateway) { this.gateway = gateway; }
}

class StockService {
  private final ProductGateway gateway;
  StockService(ProductGateway gateway) { this.gateway = gateway; }
}

@Configuration
class GatewayConfig {
  @Bean
  ProductGateway productGateway() {
    return new ProductDbGateway();
  }
}

1箇所変更の具体例

ここで外部APIへ切り替える場合、変更は原則この設定1箇所です。 利用側クラス(受注・在庫)は触りません。

@Configuration
class GatewayConfig {
  @Bean
  ProductGateway productGateway() {
    // 変更前: return new ProductDbGateway();
    return new ProductApiGateway();
  }
}

これが「配線を1箇所変えればいい」の意味です。 interface は前提として必要ですが、 DI で配線を集約しないと修正箇所は減りません。

Java 1.4 時代の感覚で言うと、Factory/Assembler を1箇所に集める設計を、フレームワークが標準化したものが現在の DI コンテナです。