本記事について
本記事ではDI(依存性の注入、Dependency injection)について出来る限りシンプルに紹介します。
DIに関連の深いDIコンテナやService Locatorは次の記事で触れる予定です。
DIの概要
DIはその名の通り依存性を注入する設計パターンです。
ClientクラスがServiceクラスを利用して機能を実現している場合に、ClientはServiceがなければ成り立ちません。
class Client {
private val service = Service()
fun search(): String {
return service.request()
}
}
class Service {
fun request(): String {
return "requested"
}
}
この関係を、ClientはServiceに依存していると言います。
この依存をClientで決めずに外から注入する設計パターンをDIと呼びます。
DIの実装
実装の準備
依存関係を外から注入するためにはServiceのInterfaceを定義する必要があります。
class Client {
private val service: ServiceInterface
fun search(): String {
return service.request()
}
}
interface ServiceInterface {
fun request(): String
}
class Service: ServiceInterface {
override fun request(): String {
return "requested"
}
}
これで準備は整いました。
ここからの実装は以下の3パターンがあります。
- コンストラクタ・インジェクション
- セッター・インジェクション
- インターフェース・インジェクション
コンストラクタ・インジェクション
ClientのコンストラクタでServiceを渡してDIを実現する方法です。
class Client(private val service: ServiceInterface) {
fun search(): String {
return service.request()
}
}
interface ServiceInterface {
fun request(): String
}
class Service: ServiceInterface {
override fun request(): String {
return "requested"
}
}
セッター・インジェクション
ClientにServiceのセッターで実現する方法です。
class Client {
private var service: ServiceInterface? = null
fun search(): String {
return service!!.request()
}
fun setService(service: ServiceInterface) {
this.service = service
}
}
interface ServiceInterface {
fun request(): String
}
class Service: ServiceInterface {
override fun request(): String {
return "requested"
}
}
Serviceがmutable, nullableになってしまうためあまり良いパターンではありません。
インターフェース・インジェクション
インターフェース・インジェクションの実装は複雑であまり利用ケースが想定できないためこの記事では紹介を省略します。
気になる方は以下を参照ください。
Inversion of Control コンテナと Dependency Injection パターン #インターフェース・インジェクション