はじめに
この記事では、初学者の方を対象に、Rubyにおける 依存オブジェクトの注入 について「なんとなくだけど理解できた!」となることを目標としています。
具体例にはRubyを用います。
依存オブジェクトの注入 とは
依存オブジェクトの注入(Dependency Injection、DI)は、オブジェクト間の依存関係を管理するための設計パターンです。
このパターンを使うと、コンポーネント(クラスやオブジェクト、またはインスタンス)が互いに独立して動作し、コードの再利用性やテストの容易さが向上します。
依存オブジェクトの注入は、主に以下の3つの方法で実現されます。
-
コンストラクタ注入(Constructor Injection): コンストラクタ(initializeメソッド) を通じて依存オブジェクトを渡す方法です。インスタンスが生成される際に、必要な依存関係が引数として注入されます。これにより、コンポーネントは自身で依存オブジェクトを生成する必要がなくなります。
-
セッター注入(Setter Injection): セッターメソッド を通じて依存オブジェクトを渡す方法です。インスタンスが生成された後に、セッターメソッドを使って依存オブジェクトが注入されます。これにより、必要に応じて依存オブジェクトを変更できます。
-
インターフェース注入(Interface Injection): 依存オブジェクトを渡すための専用の インターフェース(モジュール) を実装する方法です。コンポーネントは、このインターフェースを実装し、依存オブジェクトを受け取るメソッドを提供します。他のコンポーネントがこのインターフェースを通じて依存オブジェクトを提供することができます。
依存オブジェクトの注入は、コードの柔軟性を向上させ、モジュール間の疎結合を実現する ことで、メンテナンスやテストが容易になる利点があります。また、アプリケーションの構成を変更する際に、コードの変更が最小限で済むため、開発効率も向上します。
具体例
以下の例は、UserService クラスを使用してユーザー情報を取得し、それに基づいて各種サービスを提供するようなイメージです(MVCのコントローラのような感じです)。
また、UserRepository クラスはデータベースとのやりとりを担当し、ユーザー情報を検索・取得するための具体的な実装を提供するようなイメージです(MVCのモデルのような感じです)。
そして、UserService
がUserRepository
に依存しています。
コンストラクタ注入、セッター注入、インターフェース注入のそれぞれの方法を使用して、依存関係を注入しています。これにより、UserService
は疎結合で柔軟なコードになり、テストやメンテナンスが容易になります。
1. コンストラクタ注入 の具体例
コンストラクタ注入は、コンストラクタ(Rubyで言うinitializeメソッド)を使って依存オブジェクトを渡す手法です。これにより、オブジェクトが生成される際に、そのオブジェクトが依存する他のオブジェクトが引数として提供されます。これを利用することで、クラスが自身で依存オブジェクトを生成する必要がなくなります。
コンストラクタとは
コンストラクタとは、オブジェクト指向プログラミング言語において、クラスのインスタンスが生成される際に自動的に呼び出される特殊なメソッドです。
コンストラクタは、オブジェクトの初期化や、オブジェクトが使用するリソースの確保などのタスクを実行するために使用されます。
# ユーザー情報を取得し、それに基づいて各種サービスを提供するクラス
class UserService
# コンストラクタ(initializeメソッド)
def initialize(repository)
@repository = repository
end
def find_user(id)
@repository.find(id)
end
end
# データベースからユーザー情報を取得するメソッドのみを持つクラス
class UserRepository
def find(id)
# (データベースからユーザを検索するロジック)
end
end
repository = UserRepository.new
user_service = UserService.new(repository) # 依存オブジェクトの注入
user = user_service.find_user(1)
2. セッター注入(Setter Injection) 具体例
# ユーザー情報を取得し、それに基づいて各種サービスを提供するクラス
class UserService
# セッター
attr_writer :repository
def find_user(id)
@repository.find(id)
end
end
# データベースからユーザー情報を取得するメソッドのみを持つクラス
class UserRepository
def find(id)
# (データベースからユーザを検索するロジック)
end
end
repository = UserRepository.new
user_service = UserService.new
user_service.repository = repository # 依存オブジェクトの注入
user = user_service.find_user(1)
3. インターフェース注入 の具体例
# インターフェース(モジュール)
module RepositoryInjector
def inject_repository(repository)
@repository = repository
end
end
# ユーザー情報を取得し、それに基づいて各種サービスを提供するクラス
class UserService
include RepositoryInjector # モジュールをミックインする
def find_user(id)
@repository.find(id)
end
end
# データベースからユーザー情報を取得するメソッドのみを持つクラス
class UserRepository
def find(id)
# (データベースからユーザを検索するロジック)
end
end
repository = UserRepository.new
user_service = UserService.new
user_service.inject_repository(repository) # 依存オブジェクトの注入
user = user_service.find_user(1)
まとめ
依存オブジェクトの注入は3種類あり、コンストラクタ注入・セッター注入・インターフェース注入がある。
それらを用いることで オブジェクト間の疎結合を実現する ことができ、メンテナンスやテストが容易になる利点がある。
また、アプリケーションの構成を変更する際に、コードの変更が最小限で済むため、開発効率も向上する。
最後に
ここまで読んでいただきありがとうございました!!
もし本記事が少しでも理解の助けになったなら、ぜひイイね!をよろしくお願いします (*ᴗˬᴗ)⁾⁾
それではまた!(^_^)ノシ