私の理解では、ファサードは依存性注入の代替として使用されます。私が間違っている場合は修正してください。はっきりしていないのは、いつどちらを使用すべきかということです。
各アプローチの利点/欠点は何ですか? どちらをいつ使用するかをどのように判断すればよいですか?
最後に、両方を使用してみませんか? インターフェイスを参照するファサードを作成できます。Sentry 2 はこのように書かれているようです。ベストプラクティスはありますか?
私の理解では、ファサードは依存性注入の代替として使用されます。私が間違っている場合は修正してください。はっきりしていないのは、いつどちらを使用すべきかということです。
各アプローチの利点/欠点は何ですか? どちらをいつ使用するかをどのように判断すればよいですか?
最後に、両方を使用してみませんか? インターフェイスを参照するファサードを作成できます。Sentry 2 はこのように書かれているようです。ベストプラクティスはありますか?
ファサード
ファサードは、依存性注入の代わりにはなりません。
Laravel Facade は Service Locator パターンの実装であり、オブジェクトにアクセスするクリーンで美しい方法を作成します。
MyClass::doSomething();
これは静的メソッドの PHP 構文ですが、Laravel はゲームを変更し、舞台裏でそれらを非静的にすることで、美しく、楽しく、テスト可能なアプリケーションの作成方法を提供します。
依存性注入
依存性注入は、基本的に、コンストラクターとメソッドにパラメーターを渡しながら、それらを自動的にインスタンス化する方法です。
class MyClass {
private $property;
public function __construct(MyOtherClass $property)
{
/// Here you can use the magic of Dependency Injection
$this->property = $property
/// $property already is an object of MyOtherClass
}
}
それをより適切に構築するには、依存関係が注入されたコンストラクターでインターフェイスを使用します。
class MyClass {
private $property;
public function __construct(MyInterface $property)
{
/// Here you can use the magic of Dependency Injection
$this->property = $property
/// $property will receive an object of a concrete class that implements MyInterface
/// This class should be defined in Laravel elsewhere, but this is a way of also make
/// your application easy to maintain, because you can swap implementations of your interfaces
/// easily
}
}
ただし、Laravel ではクラスとインターフェースを同じ方法で注入できることに注意してください。インターフェイスを注入するには、次のようにする必要があります。
App::bind('MyInterface', 'MyOtherClass');
これにより、メソッドの 1 つが MyInterface のインスタンスを必要とするたびに、MyOtherClass の 1 つを与える必要があることを Laravel に伝えます。
ここで何が起こるかというと、このコンストラクターには「依存関係」:があり、これはIoC コンテナーMyOtherClass
を使用して Laravel によって自動的に注入されます。したがって、 のインスタンスを作成すると、Laravel は自動的に のインスタンスを作成し、それを変数 に入れます。MyClass
MyOtherClass
$class
依存性注入は、開発者が「パラメーターの自動生成」と同じくらい簡単なことを行うために作成した奇妙な専門用語です。
いつどちらを使用するか?
ご覧のとおり、これらは完全に異なるものであるため、どちらかを決定する必要はありませんが、アプリケーションのさまざまな部分でどちらを使用するかを決定する必要があります。
Facadesを使用して、コードの記述方法を容易にします。例: アプリケーション モジュールのパッケージを作成することは良い習慣です。したがって、これらのパッケージの Facade を作成することは、それらを Laravel public クラスのように見せ、静的構文を使用してそれらにアクセスする方法でもあります。
クラスが別のクラスからのデータまたは処理を使用する必要があるたびに、依存性注入を使用します。これらの依存関係のモックをクラスに「注入」できるため、コードがテスト可能になり、単一の責任の原則も実行されるためです ( SOLID の原則を参照してください)。
前述のように、ファサードは、潜在的に複雑なインターフェイスを簡素化することを目的としています。
Laravel の実装はさらに一歩進んで、Facade が「指す」基本クラスを定義できるようにします。
これにより、開発者は、基本クラスをモック オブジェクトで切り替えることにより、Facade を「モック」することができます。
その意味で、それらを使用してもテスト可能なコードを保持できます。これは、PHP コミュニティ内でいくつかの混乱が存在する場所です。
DI は、コードをテスト可能にするものとしてよく引用されます。DI を使用すると、クラスの依存関係を簡単にモックできます。(補足: インターフェイスと DI には他にも存在する重要な理由があります!)
一方、ファサードは、テストしているコードに「単純にモックオブジェクトを挿入する」ことができないため、テストを難しくするものとしてよく引用されます。ただし、前述のように、実際にはそれらを「モック」することができます。
これは、Facades が DI の代わりになるかどうかについて人々が混乱するところです。
ある意味では、どちらもクラスに依存関係を追加します - DI を使用して依存関係を追加するか、Facade を直接使用できます - FacadeName::method($param);
。(うまくいけば、クラスを別のクラス内で直接インスタンス化しないでください :D )。
これは Facades を DI の代替にするものではありませんが、代わりに、Laravel 内で、DI を使用するか Facade を使用するかの 2 つの方法のいずれかでクラスの依存関係を追加することを決定できる状況を作成します。(もちろん、他の方法を使用することもできます。これらの「2 つの方法」は、最も頻繁に使用される「テスト可能な方法」にすぎません)。
Laravel の Facade は、Facade パターンではなく、Service Locator パターンの実装です。
私の意見では、ドメイン内でサービス ロケーターを使用することは避け、サービス レイヤーと Web トランスポート レイヤーでのみ使用することを選択する必要があります。
http://martinfowler.com/articles/injection.html#UsingAServiceLocator
laravelに関して言えば、ファサードをモックできるため、コードをシンプルに保ち、テスト可能に保つのに役立つと思いますが、ファサードを使用すると、おそらくコードのいたるところにあるため、コントローラーの依存関係を伝えるのが少し難しくなる可能性があります。
依存関係の注入では、依存関係を処理するためのインターフェイスとサービスの作成に対処する必要があるため、もう少しコードを記述する必要がありますが、コントローラーのコンストラクターで明確に言及されているため、コントローラーが依存するものについては後でより明確になります。
どちらの方法を使用するのが好きかを決める問題だと思います