私は、最近PHPとLaravelに触れ始めた初心者エンジニアなのですが、
Laravelのドキュメントを読んでいたら「依存」という言葉がたくさん出てきて、
わからなかったので調べてみたら、とても理解が難しかったので、分かった点を
まとめてみました。
#Dependency Injection(DI)とは
日本語では「依存性の注入」と訳される。
「あるオブジェクトを、それを使用するオブジェクトに渡す」
というデザインパターンの1つ。
##DIパターンの例 ① コンストラクタ・インジェクション
// 使用する側のクラス
class Client
{
private $service;
// コンストラクタでServiceオブジェクトを渡している。
public function __construct(Service $service)
{
$this->service = $service;
}
public function doSomething()
{
$this->service->doSomething();
}
}
// 使用される側のクラス
class Service
{
public function doSomething()
{
// 処理
}
}
上記のコードではコンストラクタを使ってオブジェクトを渡しているため、
「コンストラクタ・インジェクション」と呼ばれる。
オブジェクトの渡し方によって、DIパターンの手法は以下のようなものもある。
##DIパターンの例 ② メソッド・インジェクション
メソッドの引数にオブジェクトを渡す。
// 使用する側のクラス
class Client
{
// メソッドでServiceオブジェクトを渡している。
public function doSomething(Service $service)
{
$service->doSomething();
}
}
// 使用される側のクラス
class Service
{
public function doSomething()
{
// 処理
}
}
##DIパターンの例 ③ セッター・インジェクション
DI用のセッターを用意してオブジェクトを渡す。
// 使用する側のクラス
class Client
{
private $service;
// DI用のセッターを用意してServiceオブジェクトを渡している。
public function setService(Service $service)
{
$this->service = $service;
}
public function doSomething()
{
$this->service->doSomething();
}
}
// 使用される側のクラス
class Service
{
public function doSomething()
{
// 処理
}
}
##【DIパターンでない例】
// 使用する側のクラス
class Client
{
private $service;
public function __construct()
{
// コンストラクタ内でServiseオブジェクトを生成している。
$this->service = new Service();
}
public function doSomething()
{
$this->service->doSomething();
}
}
// 使用される側のクラス
class Service
{
public function doSomething()
{
// 処理
}
}
###DIパターンの特徴
- オブジェクトの生成と仕様が分離されている
- クライアントがサービスを呼ぶのではなく、サービスが外部からクライアントに注入される。つまり、制御が反転している。
DIパターンでない場合、ClientオブジェクトはServiceオブジェクトがないと動作できないため、**「ClientはServiceに依存している」**ということになる。
「依存」と訳されるのはそういう事のようだ。
##抽象への依存
class Client
{
private $service;
// コンストラクタ
// 実行時に、ServiceInterfaceインターフェースを実装したクラスのオブジェクトが
// 渡されれば実行できる。
public function __construct(ServiceInterface $service)
{
$this->service = $service;
}
public function doSomething()
{
$this->service->doSomething();
}
}
// ServiceInterfaceインターフェイス
interface ServiceInterface
{
public function doSomething();
}
// ServiceInterfaceを実装したServiceクラス
class Service implements ServiceInterface
{
public function doSomething()
{
// 処理
}
}
上記のコードでは、ClientはServiceinterfaceインターフェイスを実装したオブジェクトがあれば動作できる。
Serviceオブジェクトに限らず、Serviceinterfaceインターフェイスを実装したオブジェクトがあれば良いので、このような場合は**「抽象に依存している」**という。
###【疎結合】
この場合、オブジェクトをDIで別の実装(クラス)に差し替えることができて、
ClientとServiceの**(クラス間の)結合度が緩くなる。**疎結合という。
###【密結合】
DIパターンではないコードの場合(ClientがServiceに依存している場合)、
ClientとServiceの**(クラス間の)結合度がきつい。**密結合という。
#手動でのDI
上記の例で、Clientクラスを使うには以下のようにする。
DIパターンは、「あるオブジェクトを、それを使用するオブジェクトに渡す」
パターンなので、
使用されるオブジェクトを使用するオブジェクトの外部で生成し、使用するオブジェクトに注入することで、DIパターンを使用していると言える。
以下のようなコードを**「手動でのDI」**という。
// Serviceオブジェクト(使用される側)の生成
$service = new Service();
// Clientオブジェクト(使用する側)に注入 手動DI
$client = new Client($service);
DIパターンについては、こういうものがあるんだということを知れて、触りだけ
でも理解できたので良かった。
Laravelでは、DIにまつわる部分を担当する「サービスコンテナ」を中心として
フレームワークが作られているようなので、次はサービスコンテナについて理解
したいと思う。
#参考資料