依存関係逆転の原則(DIP)
DIP
上位のモジュールは下位のモジュールに依存してはならない。どちらのモジュールも「抽象」に依存すべきである 「抽象」は実装の詳細に依存してはならない。実装の詳細が「抽象」に依存すべきである
https://medium.com/eureka-engineering/go-dependency-inversion-principle-8ffaf7854a55
DIPはレイヤーに依存するのではなく抽象に依存するという原則です。
言葉だけだと伝わりにくいのでコードで記述をしていきます。
DIP違反をしているコード
下位レイヤーが上位レイヤーに依存しているコードです。
上位クラスであるボールペンは黒い芯に依存しています。もしボールペンの色を赤い芯に変えて使いたい時BallPenクラスに修正が必要になってしまいます。
class BlackCore {
private let color = "black"
func printColor(){
print(color)
}
}
class BallPen {
let core: BlackCore
init(core: BlackCore) {
self.core = core
}
func printColor() {
core.printColor()
}
}
//BlackCore以外のクラスを渡せない
let pen = BallPen(core: BlackCore())
pen.printColor()
図で表すと以下の様になります。ボールペンがボールペンの芯に依存している状態です。
DIPを守った実装
新規にCoreというprotocolを定義しボールペンの芯クラスに準拠させました。
各芯クラスがCoreに準拠していることで、BallPenクラスのInitializerに渡す型をCoreに変えることができました。
protocol Core {
func printColor()
}
class BlackCore: Core {
let color = "black"
func printColor(){
print(color)
}
}
class RedCore: Core {
let color: String = "red"
func printColor() {
print(color)
}
}
class BallPen {
let core:Core
init(core: Core) {
self.core = core
}
func printColor() {
core.printColor()
}
}
//ボールペンのインスタンス作成時に色を決める
let redBallPen = BallPen(core: RedCore())
redBallPen.printColor()
図で表すと以下の様になります。DIP違反を起こしているコードではボールペンが芯クラスに依存する形になっていましたが、Coreに準拠することによって依存関係が逆転しました。
Coreに準拠した形であれば、青でも緑でも好きな色を増やしボールペンにセットすることが可能です。BallPenクラスは特定の芯に依存していないため、新しく芯クラスを作成してもBallPenクラスに変更が及ばないのが利点です。