これは本当に依存性注入の背後にある理論です。
「新しい」を使用すること自体が悪い考えではありません。むしろ、クラス内でオブジェクトをインスタンス化することにより、クラス自体を変更せずに変更または切り替えることのできないハードな依存関係を作成しています。
また、「実装ではなく、インターフェースへのコーディング」というパラダイムにも違反しています。
例:
class Phone {
protected $network;
public function __construct() {
$this->network = new Verizon();
$this->network->distinctiveRing();
}
}
class Verizon {
public function call($number) {
....
}
public function distinctiveRing() {
}
}
さて、ある日、ATT、TMobile、Sprintの電話を作りたいと思ったとしましょう。確かに彼らは皆電話をかけることができ、電話番号だけで電話をかけることができます。また、電話クラスは、実際にネットワーク接続を確立するのではなく、番号の入力を容易にすることが仕事であるため、キャリアが誰であるかを気にする必要はありません。
つまり、SprintPhone
別のSprintネットワークオブジェクトをインスタンス化できる新しいクラスを作成する必要はありませんよね?右。
それで、より良い方法は何ですか?
class Phone {
protected $network;
public function __construct(NetworkInterface $network) {
$this->network = $network;
}
}
interface NetworkInterface {
public function call($number);
}
class Verizon implements NetworkInterface {
...
}
class Sprint implements NetworkInterface {
...
}
さて、あなたはただ言うことができます:$phone = new Phone(new Sprint())
または$phone = new Phone(new Verizon())
distinctiveRing
また、への呼び出しがなくなったことにも注意してください。なんで?ええと、NetworkInterfaceを実装するオブジェクトが必ずしも独特のリングをサポートするかどうかはわかりません。しかし、これは良いことです。コードを変更せずにすべてPhone
をサポートできるようになったからです。 Network
特徴的なリングのサポートが必要な場合は、distinctiveRing
メソッドをサポートする新しいインターフェイスをいつでも作成できます。あなたのPhone
オブジェクトでは、あなたはあなたの道具があるかどうかをチェックすることができNetwork
、 DistinctiveRingerInterface
もしそうなら、あなたの独特のリングを作ることができます。しかし、このアプローチでは、特定のネットワークに縛られることはなくなります。さらに良いことに、最初から正しいアプローチをとったため、これを行うことを余儀なくされました。
そして、将来的に実現可能に作成できる他のネットワーク。さらに重要なことに、クラスは、与えられたネットワークオブジェクトの種類を気にする必要がなくなりました。(NetworkInterfaceを実装するオブジェクトを受け取ったため)、Network
オブジェクトが。を使用してを作成できることを認識しcall
ています$number
。
これはまた、関心の分離を改善して、はるかに優れたコードにつながる傾向があります。
そして最後に:テスト。
最初の例では、Phoneオブジェクトをテストしようとすると、Verizonネットワークで電話をかけることになります。あなたがユニットテストを実行しているので、一日中呼ばれる人になるのは嫌ですよね?右。
さて、NetworkInterfaceを実装するTestNetworkクラスを作成し、それを電話オブジェクトに渡すだけです。TestNetworkクラスは、そのcall
メソッド内で必要なことをすべて実行できます。または、何も実行できません。
さらに、を使用してモックオブジェクトを作成し、TestNetworkPHPUnit
のメソッドが実際に呼び出されるようにすることができます。は内部でインスタンス化されていcall
たため、以前はこれを行うことができませんでした。Network
Phone