依存関係逆転の原則(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クラスに変更が及ばないのが利点です。

参考文献

依存関係逆転の原則の重要性について

依存関係逆転の原則