4

最近、コンストラクターで「new」というキーワードを使用することは非常に嫌われていると読みましたが、その理由がよくわかりません。たとえば、次のようになります。

class A {
    public $foo;

    function __construct() {
        $this->foo = new Bar();
    }
}

以下と異なるもの:

class A {
    public function someMethod() {
        $foo = new Bar();
    }
}

???

4

3 に答える 3

14

これは本当に依存性注入の背後にある理論です。

「新しい」を使用すること自体が悪い考えではありません。むしろ、クラス内でオブジェクトをインスタンス化することにより、クラス自体を変更せずに変更または切り替えることのできないハードな依存関係を作成しています。

また、「実装ではなく、インターフェースへのコーディング」というパラダイムにも違反しています。

例:

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たため、以前はこれを行うことができませんでした。NetworkPhone

于 2013-01-08T17:01:15.767 に答える
3

あなたの質問とあなたのコード例はあまり共有していないようですか?

クラス変数に割り当てるため、最初のコードサンプルは機能するはずです。

class A {
    public $foo;

    function __construct() {
        $this->foo = new Bar();
    }
}

2番目のサンプルは、それを__construct()メソッドのローカル変数に割り当てるため、後で値を取得する機会はありません。

class A {
    public function someMethod() {
        $foo = new Bar();
    }
}

その上:新しいものを使用することは通常問題ありません。ただし、制御の反転またはIOCについて読んだことがあるかもしれません。これは、依存関係を回避するための手法であるため、コンストラクターで直接クラスを作成しないようにする必要があります。たとえば、http://ralphschindler.com/2011/05を参照してください。 / 18 / Learning-about-dependency-injection-and-php

于 2013-01-08T16:53:44.757 に答える
1

最初の例では、$ fooはこのクラスの任意のメソッドで使用でき、オブジェクトの外部でも使用
できるため、次のことができます。

$a = new A();
$a->foo->sth;

2番目の例では、$fooはsomeMethod内でのみ使用できます。

于 2013-01-08T16:52:17.220 に答える