OOPにおける依存とは

概要

OOPではよく「抽象に依存させる」「依存性の逆転」等、 "依存" という言葉が出てきます。 この "依存" とはどういう意味なのか、最近やっとわかってきたのでメモを残したいと思います。 (Javaで解説します、Javaアレルギーの方は我慢して下さい)

この記事は僕が思っていることなので、間違いがありましたらコメント頂けると幸いです。

依存とは

依存とは、実装の詳細を知っていることです。

コード上での依存とは、下記のようにnewしている状況を指します。
下記コードでは A が B を new しているので、 A は B に依存しているということになります。

class B { ... }

class A {
  public void example() {
    B b = new B();
  }  
}

依存している状況では、依存先が変更された場合依存元も変更が強いられます。

抽象に依存させる

抽象とは抽象クラスやインタフェースを指します。
new して受け取る型を new するクラスの抽象クラスやインタフェースの型にします。

interface C { ... }

class B implements C { ... }

class A {
  public void example() {
    C c = new B();
  }
}

抽象に依存させることのメリットは、実装が変わったとしても依存元は実装の詳細を知らないので影響を受けないことです。 これにより、変更に強いコートを生み出すことが出来ます。

依存性の注入(DI)とは

最近良く聞く奴です、クラス内で new するのではなくすでに new した物を受け取ることで実現します。

下記コードでは A の生成元である D で B を new して A のコンストラクタ引数に渡しているので、A は B には依存していません。
その代わり、D は A と B に依存することになります。(このような方法をコンストラクタインジェクションというそうです)

class B { ... }

class A {
  private B b;  

  A(B b) {
    this.b = b;
  }
}

class D {
  public void test() {
    A a = new A( new B() );
  }
}

依存性の注入を行うことで、依存先が実装されていなくてもテストすることが出来ます。
DIコンテナは依存性の注入を肩代わりしてくれる奴だそうです。※要出典

CleanArchitectureのこと

CleanArchitectureは円状になっており、円の内側にしか依存させないという特徴があります。 円の一番外側にはDBにアクセスするようなクラスがありますが、これをビジネスロジックから利用するには依存性の注入を行います。

外側にDBにアクセスするクラスがあるのはDB等の実装はビジネスロジックよりも変化が激しい為、どこにも依存しないようにするためです。

まとめ

コードは常に変更に強くあるべきなので、なるべく抽象に依存させましょう。