はじめに
Javaの学習を初めてしばらく経ったので、設計力を上げるため、SOLID原則を学んでいる。
学んだ内容について自分の中で咀嚼するため記事を書いてみた。
依存関係逆転の原則(Dependency Inversion Principle)とは何か
SOLID原則の一つであり、ソフトウェアモジュールを疎結合に保つための原則、方法論のこと。
下記のような原則が述べられている。
A. 上位レベルのモジュールは下位レベルのモジュールに依存すべきではない。両方とも抽象(abstractions)に依存すべきである。
B. 抽象は詳細に依存してはならない。詳細が抽象に依存すべきである。
引用 : https://ja.wikipedia.org/wiki/依存性逆転の原則
そもそも依存関係とは何か
一言で表すと、クラス間の結びつきのことである。
簡単なコードで例を表してみる。
public class Customer {
public void pay(){
BankingPayment payment = new BankingPayment();
payment.execute();
}
}
public class BankingPayment{
public void execute() {
//銀行支払い処理
}
}
CustomerとBankingPaymentの2つのクラスがあり、Customerクラス内部でBankingPaymentインスタンスを生成している。この状態はCustomerクラスがBankingPaymentクラスに依存している状態だと言える。
この状態では、BankingPaymentクラスの変更時にCustomerクラスまで変更しなければならない。(executeメソッドの返り値や引数の変更されるケース)
つまりBankingPaymentクラス(=下位レベルモジュール)が変更された時、Customerクラス(=上位レベルモジュール)までも変更の影響を受けているということになる。
また仕様や機能追加により別の決済方式が必要になった場合、先の例ではCustomerクラスで呼び出されているBankingPaymentクラスの部分すべてを変更する必要がある。
変更の影響を受けないためにはどうすべきか
変更されやすいものには依存せず、安定したものに依存すればよい
安定した抽象と変化しやすい具象
インターフェイスは変化しにくいが、実装クラスは変化しやすい。
そのため、変化しやすい具象(=実装クラス)には依存せず、安定しているインターフェイス(=抽象)に依存させる。
interface Payment{
void execute();
}
public class Customer {
public void pay(){
Payment payment = new BankingPayment();
payment.execute();
}
}
public class BankingPayment implements Payment{
@Override
public void execute() {
//銀行支払い処理
}
}
この状態では、CustomerクラスはPaymentインターフェイスに依存しているが、BankingPaymentクラスには依存しなくなった。そしてPaymentインターフェイスをBankingPaymentクラスが実装している。
つまり、上位レベルモジュール(Custmer)が所有するPaymentインターフェイスにBankingPaymentクラスが依存することになり、依存関係が先の例と比べて逆転していることがわかる。
また先の例で決済方法が銀行支払いからクレジット支払いに変更された場合でも、新たにPaymentインターフェイスからCreditPaymentクラスを実装すればよいため、Customerクラスでの変更範囲は最小限に抑えることができる。
まとめ
変化しやすい具象モジュールには依存させず、インターフェイスを作成し、依存関係を逆転させることで柔軟にシステムの変化に対応できるようになる。