2024-07-20
2024-07-20
How to implement Dependency Injection Pattern in Ruby On Rails?
https://dev.to/vladhilko/how-to-implement-dependency-injection-pattern-in-ruby-on-rails-28d6
class LoggerService
def self.call(params)
puts params
end
end
class Service
def call
LoggerService.call('Something happened')
end
end
Service.new.call
このハードコードアプローチの問題点:
- SOLIDの依存関係逆転の原則に反する
- クラスの内部メソッドを更新する必要があるため、コードを変更するのはかなり難しく、何かを壊してしまう危険性がある
- 内部でハードコードされたサービスをたくさん使い始めると、読んで理解するのが難しくなる。 例えば、ハードコードされたサービスは複数の名前空間(Namespace1::Namespace2::LoggerServiceなど)の下にある可能性があるので、本当に「認知的負荷」が増えます)。
Plain Ruby Dependency Injection
記事では dry gem を使った例もあるがやらない
class Service
attr_reader :logger_service
def initialize(logger_service:)
@logger_service = logger_service
end
def call
logger_service.call('Something happened')
end
end
# Now you can inject any logger service you want into the Service class
service = Service.new(logger_service: LoggerService)
service.call
依存関係の逆転の説明
依存関係の逆転の原則は、オブジェクト指向設計のSOLID5原則の1つである。
- 高レベルモジュール(クラスやコンポーネントなど)は、低レベルモジュールに依存してはならない。
- 抽象化は詳細に依存すべきではない。 詳細(具体的な実装)は抽象に依存する必要があります。
提供されたコード例のコンテキストでは、Service クラスは高レベルモジュールと見なされ、LoggerService クラスは低レベルモジュールと見なされます。 依存性注入を使用することで、Service クラスは LoggerService クラスの特定の実装に依存しなくなり、代わりに抽象化(つまり、params 引数を受け入れる呼び出しメソッドを持つオブジェクト)に依存します。
これは依存性の逆転の原則に従います。なぜなら、高レベルの Service クラスは、低レベルのモジュール(LoggerService クラス)ではなく、抽象化(logger_service
オブジェクト)に依存するからです。 また、詳細(LoggerService クラスの具体的な実装)が抽象(logger_service
オブジェクト)に依存するため、この原則に従います。
全体として、依存性注入を使用し、依存性の逆転の原則に従うことで、ソフトウェアの設計とアーキテクチャを改善することができます。