今回はSOLIDの依存関係逆転の原則についてまとめました。
その他の記事は以下。
きれいなコードを書くためにSOLID原則を学びました① ~単一責任の原則~
きれいなコードを書くためにSOLID原則を学びました② ~オープン・クローズドの原則~
きれいなコードを書くためにSOLID原則を学びました③ ~リスコフの置換原則~
きれいなコードを書くためにSOLID原則を学びました④ ~インターフェース分離の原則~
#依存関係逆転の原則
High-level modules should not depend on low-level modules. Both should depend on abstractions.
直訳すると、**「ハイレベルのモジュールはローレベルのモジュールに依存するべきではない。両方とも抽象に依存するべきである」**という意味になります。
「ハイレベル」やら「ローレベル」やら「抽象」といった見慣れない言葉が出てきましたね...
四角で囲まれているものがアプリケーションのそれぞれの機能を示しており、これをモジュールと呼びます。
PayPalやGooglePayのモジュールをみてみると、これらはPaymentProcessor(支払処理)の具体的なサービス名にあたります。このように、PaymentProcessorのような一般的な機能にあたる部分をハイレベル、具体的な手段にあたる部分をローレベルと呼びます。ただ、図のCommunicationのような、CustomerProfileからみたらローレベル、EmailSenderからみたらハイレベルみたいなモジュールもあるので、レベルというのはあくまで相対的な概念であるという点に注意が必要です。
言葉の定義がわかったところで図をみてみると、何か違和感を感じるはずです。
そうです。「ハイレベルのモジュールはローレベルのモジュールに依存するべきではない。」という原則に違反してしまっています。
##インターフェースの導入
ProductCatalogとSQLProductRepositoryの関係について、図の依存関係をコードにすると以下のようになります。
モジュールの依存というのは、要は他のモジュール内でインスタンス化を行っていることとみなすことができます。
public class ProductCatalog {
public void listAllProducts() {
SQLProductRepository sqlProductRepository = new SQLProductRepository();
}
}
public class SQLProductRepository {
public List<String> getAllProductNames() {
...
}
}
この依存関係を解消する方法は、インターフェースとインスタンス化を行うファクトリークラスを利用することです。
public class ProductCatalog {
public void listAllProducts() {
ProductRepository productRepository = ProductFactory.create();
...
}
}
public interface ProductRepository {
public List<String> getAllProductNames();
}
public class ProductFactory {
public static ProductRepository create() {
return new SQLProductRepository();
}
}
public class SQLProductRepository implements ProductRepository {
public List<string> getAllProductNames() {
...
}
}
インターフェースを挟むことでモジュール間の依存関係はなくなり、インタフェースが両モジュールから依存されるようになります。
このように、依存される側だったSQLProductRepositoryが依存する側に逆転することから、依存関係逆転の原則と呼ばれます。
#おわりに
依存性の注入については、Laravelを例にしてまた別の機会にまとめてみたいと思います。
#参考書籍・動画
Crean Architecture Robert.C.Martin
SOLID Principles: Introducing Software Architecture & Design Sujith George