17

別のクラス内でクラス オブジェクトを使用することに関して、ベスト プラクティスは何ですか? class _construct ステートメントでクラス オブジェクトを渡すか、新しいクラス オブジェクトを作成しますか?

例 1:

class Foo {
    private $bar;

    public function __construct($bar){
       $this->bar = $bar;
   }
}

または例 2:

class Foo {

    private $bar;

    public function __construct(){
        $this->bar= NEW bar;
    }    
}

クラスファイルがすでに別の場所に含まれている必要があることは当然のことであり、最初のインスタンスでは、このタイプのクラスオブジェクトが既に存在する必要があることは明らかですが、各メソッドの利点を知りたいです、データベース オブジェクトを使用するコードを作成する必要があるクラスが多数あるため、これをクラスに渡す最善の方法が必要です。これら 2 つよりも優れた 3 番目のオプションはありますか?

私が理解できることから、最初の利点は、コーディング行が数行少なくなり、DB の場合は新しい接続が作成されないことです。自己完結型なので、2 番目の方が良いかもしれません。とにかく専門家に聞いてみようと思いました。

4

6 に答える 6

13

最初。(このアプローチはDependency Injectionと呼ばれます)。

コンストラクターは、問題のオブジェクトが機能するために必要なものは何でも要求します。このように、メソッドだけで (何が必要で、何を返すか)、それが何をするかはかなり明確です。ソースコードを見なくても。

コードを改善する方法は、メソッドに型ヒントを導入することです。

class Foo {
    private $bar;

    public function __construct(Bar $bar){
       $this->bar = $bar;
   }
}

Barオブジェクトのみが渡されるようにします。


依存性注入の利点

  • 非常に読みやすい。
  • ソース コードを表示せずにメソッドの依存関係を伝える機能。
  • 単体テストを可能にします。
  • *子猫を神の怒りから救います。

*免責事項:この回答の出現中に子猫は害を受けませんでした

于 2012-10-24T09:31:28.760 に答える
10

これは依存性注入の最も単純な形式であるため、オプション 1 を使用する必要があります。

オプション 1:

  • クラスは互いに独立している
  • バークラスのモックを使用して、クラスを独立してテストできます
于 2012-10-24T09:30:18.300 に答える
8

一般に、ユニットテストに関して「新しい」オペレーターについて考える方法で概説されている理由で、私はDI群衆とチャイムを鳴らします。

しかし、依存性注入が非常に重要である理由は、単体テスト内でアプリケーションの小さなサブセットをテストしたいからです。要件は、システム全体から独立して、アプリケーションのその小さなサブセットを構築できることです。アプリケーションロジックとグラフ構築(新しい演算子)を組み合わせると、アプリケーションのリーフノード以外では単体テストが不可能になります。

コードをクリエーターグラフとコラボレーターグラフに分けると、コードの保守とテストが可能になります。さらに良いことに、インターフェースに対するコードを作成すると、具体的な実装を他の実装と交換するのが非常に簡単になります。これにより、ハードコードされた依存関係を探すためにコードを探す必要がなくなるため、コードの変更が簡単になります。

たとえばBar、ロガーが必要だとすると、

class Foo
{
    private $logger;

    public function __construct(LogInterface $logger)
    {
        $this->logger = $logger;
    }
}

LogInterface次に、データベースロガー、StdOutLogger、またはこれらの両方を保持する複合ロガーなど、それを実装する具体的な実装を渡します。もう1つの例は、Databaseオブジェクトです。ブートストラップで一度作成し、それを使用してオブジェクトに渡すことができます。

疑わしい場合は、依存性注入を使用してください。

ただし、必ずしも何かを注入する必要はありません。オブジェクト(バー)がInjectableであるかNewableであるかによって異なります。Misko Heveryを引用するには:

Injectableクラスは、コンストラクターで他のInjectableを要求できます。[…]注射剤は、テストに適した実装に置き換える必要がある可能性があるため、インターフェイスを持つ傾向があります。ただし、Injectableは、コンストラクターでInjectable以外(Newable)を要求することはできません。これは、DIフレームワークがNewableを生成する方法を知らないためです。[…]Newablesの例としては、Eメール、MailMessage、ユーザー、クレジットカード、歌などがあります。この区別を維持すると、コードのテストと操作が簡単になります。このルールに違反すると、コードのテストが困難になります。

一言で言えば、ユーザー提供または実行時の情報に基づいているため、合理的に注入できないものがある場合は、それを実行できnewます。これは、値オブジェクトとデータ型に特に当てはまります。

class Foo
{
    private $storage;

    public function __construct()
    {
        $this->storage = new SplObjectStorage;
    }
}

注入しても意味がありませんSplObjectStorage。これは単なるデータ型です。

于 2012-10-24T09:39:49.553 に答える
0

1番目のオプションを使用すると思います。そうしている間、抽象化へのプログラミングは実装へのプログラミングよりも良い考えだと思います。

最初のオプションは集約の形式であり、2 番目のオプションは構成の形式です。抽象化で得られる利点は、クラス FOO を使用するクライアント クラスが、コンストラクターに送信することを決定したインターフェイスの特定の実装に基づいて、FOO に何らかのアクティビティを実行させることができることです。

以下の AC# の例

    class Foo {
    private IBar bar;

    public Foo(IBar obj){
       this.bar = obj;
   }

   public void myFooMethod()
   {
      bar.ExecuteMethod();
   }
}

FOOを呼び出すクラス

    public class MyCallingClass
    {

       public void CallFooMethod()
       {
          IBar bar1Obj = new BAR1();
          Foo fooObject = new Foo(bar1Obj);
          fooObject.ExecuteMethod();
//or
          IBar bar2Obj = new BAR2();
          fooObject = new Foo(bar2Obj);
          fooObject.ExecuteMethod();
//or
          IBar bar3Obj = new BAR3();
          fooObject = new Foo(bar3Obj);
          fooObject.ExecuteMethod();

       }

    }

これで、呼び出し元のクラスは IBar の実装を FOO クラスに渡すことができます。

これが役に立ったことを願っています。

于 2012-10-24T14:37:44.317 に答える
0

依存性注入は素晴らしく、役に立ち、子猫を救うので、詳しく説明するつもりはありません。

代わりに、両方のソリューションを実装することをお勧めします。

class Foo {
    private $bar;

    public function __construct($bar = null){
       $this->bar = isset($bar) ? $bar : new Bar();
   }
}

そうすれば、デフォルトでデフォルトのクラスを使用でき、機能を変更する必要がある場合は、それも行うことができます。

于 2012-10-24T14:55:32.133 に答える
0

他の人がすでにあなたの質問に答えています - 依存性注入を使用する最初のアプローチを確実に使用してください。

私は、あなたが気付いていない可能性のある別の一般的な代替手段、つまり Dependency Injection Containerを使用してチップを入れたかっただけです。

これの素晴らしい、簡単な例はPimpleです。Symfony フレームワークの背後にいる人物である Fabien Potencier によって開発されました。

例 3:

# In a bootstrap file...
require_once '/path/to/Pimple.php';

$container = new Pimple();
$container['bar'] = function ($c) {
    return new Bar(/** If bar has dependencies, put them here **/);
};

$container['foo'] = function ($c) {
    return new Foo($c['bar']);
};

# You'd still inject the service using DI, because it's not good 
# practice for your objects to rely directly on the container

class Foo {
    private $bar;

    public function __construct($bar){
       $this->bar = $bar;
   }
}

# The difference would be how you call Foo...
$foo = $container['foo'];

# So now your code doesn't need to know about the dependencies, and it's easy 
# to change them at any time by making a single change in your configuration

Symfony2 はより堅牢なコンテナを使用しており、これはスタンドアロン コンポーネントとしても利用できます。ただし、大規模なアプリケーションを開発する場合を除き、おそらく Pimple が最善の策です。

于 2012-10-24T09:48:12.350 に答える