Dependency Injectionって「依存性の注入」じゃないの?
やっていることは、 依存しているオブジェクトを注入するようにする なので、「依存オブジェクトの注入」の方が訳としてただしいのでは? という議論がある
little-hands.hatenablog.com
あと、自分が読んでいるオブジェクト指向設計実践ガイドでも「依存オブジェクトの注入」が採用されているので、こちらを使う
依存オブジェクトの注入 ってどういう時の使うの?
依存性が高いオブジェクトを内包している時。そのオブジェクトを外部から注入するように修正する
具体的にはこんなコード(オブジェクト指向設計実践ガイドより)
class Gear
attr_reader :chainring, :cog, :rim, :tire
def initialize(chainring, cog, rim, tire)
@chainring = chainring
@cog = cog
@rim = rim
@tire = tire
end
def gear_inches
ratio * Wheel.new(rim, tire).diameter
end
end
Gear.new(52, 11, 26, 1.5).gear_inches
このコードのどこが問題なの?
ギアのインチを計算する Gear#gear_inches
が、Wheel
に 依存した状態 である
結果的に以下のような問題が発生する
- 変更時のコストが高い
- 例えば
Wheel.new
のためだけに、rim
と tire
が Gear#initialize
に渡されている。そのため、Wheel.new
の引数が変わったら、Gear
は大幅に変更が必要になる
- そもそもここに
Wheel
があることを知らなければ、修正が必要なことにも気が付けない
- 再利用性が低い
Wheel
以外のオブジェクトからギアを計算したい時、別のメソッドが必要
- テスト実装のコストが高い
- テストを書く時に、
Wheel
オブジェクトのことを考慮する必要がある
じゃあどんなふうに直したら良いの?
こんなふうに、Gear
に対して外部から、diameter
を呼べるオブジェクトを注入してあげれば良い
class Gear
attr_reader :chainring, :cog, :wheel
def initialize(chainring, cog, wheel)
@chainring = chainring
@cog = cog
@wheel = wheel
end
def gear_inches
ratio * wheel.diameter
end
end
Gear.new(52, 11, Wheel.new(26, 1.5)).gear_inches
こうすれば、 Gear
は、Wheel
に依存しなくなり、
wheel
については #diameter
さえ実行できればどんなオブジェクトでも良くなる → ダックタイピング
なので、Wheel
が変更されてね影響は少なくなるし、テストするときも簡単な mock を作れば良いだけになる
蛇足
むしろ、「依存性オブジェクトの排除」とか言ったほうが意味が通じそう、という話を会社のQiita::Teamでした