0

オブジェクト指向の設計パターンを使用しているので、本当に理解しているかを確認したいと思います。依存性注入の重要性と、サービス コンテナー/ファクトリ オブジェクトについても理解しています。静的メソッドを介してロードされたときに依存関係を自分自身に注入し、完全な自分自身のコピーを返すことができるファクトリ メソッドのアイデアが気に入っています。オブジェクトを消費するコードがすっきりしていて気に入っています。また、テストでは、代わりに別のオブジェクトを注入できます (ファクトリ メソッドを使用せずに上書きまたはインスタンス化します。以下を参照)。

次のコードについて警鐘を鳴らすものはありますか? 私はこれを正しく理解していますか?

abstract class AbstractClass
{
    public function __construct ()
    {

    }

    public static function factory ()
    {
        throw new Exception ('Please create a concrete class version of the method ' . __FUNCTION__);
    }

    public function inject ($class, $className=null)
    {

        if ($className === null)
        {
            $className          = get_class ($class);
        }

        $this->{$className} = $class;
    }
}

class ConcreteClass extends AbstractClass
{
    public static function factory ()
    {
        $me = new self;
        $me->inject (RebarClass::factory ());
        $me->inject (AsphaltClass::factory ());
        $me->inject (CementClass::factory ());

        return $me;
    }

    public function doSomething ()
    {
        echo $this->RebarClass->doSomethingCool ();
    }

}

class RebarClass extends AbstractClass
{
    public static function factory ()
    {
        return new self;
    }

    public function doSomethingCool ()
    {
        return "I did something, but it wasn't that cool...\n";
    }
}

class AsphaltClass extends AbstractClass
{
    public static function factory ()
    {
        return new self;
    }
}

class CementClass extends AbstractClass
{
    public static function factory ()
    {
        $me = new self;
        $me->inject (AsphaltClass::factory ());
        $me->inject (SandClass::factory ());

        return $me;
    }
}

class SandClass extends AbstractClass
{
    public static function factory ()
    {
        return new self;
    }
}

私にとって、これにより、コントローラーやその他のモデルでオブジェクトを作成および使用するときに多くの柔軟性が得られます。次のようにインスタンス化できます。

$concreteClass = ConcreteClass::factory ();

そして今、私のオブジェクトは私が望むように設定されています

print_r ($concreteClass);
echo "\n";

出力:

ConcreteClass Object
(
    [RebarClass] => RebarClass Object
    (
    )

    [AsphaltClass] => AsphaltClass Object
    (
    )

    [CementClass] => CementClass Object
    (
        [AsphaltClass] => AsphaltClass Object
        (
        )

        [SandClass] => SandClass Object
        (
        )

    )

)

そして、内部的に他のオブジェクトは使いやすいです

echo $concreteClass->doSomething ();

これを単体テストに使用する場合は、次のいずれかを実行できます。

$concreteClass = ConcreteClass::factory ();
$concreteClass->inject(new DifferentAsphaltClass, 'AsphaltClass'); // overwrite

また

$concreteClass = new ConcreteClass; // now you are responsible for setting up dependencies yourself
$concreteClass->inject (new YetAnotherAsphaltClass, 'AsphaltClass');
4

1 に答える 1

1

提示されたアプローチには、ファクトリを使用しない場合に必要なクラスを適切に注入することに関連するいくつかのリスクがあります。

必要なインジェクションのリストが利用できないため、コードを理解するのも少し難しくなります。

inject メソッドを使用する代わりに、クラス コンストラクターを依存関係の受信者として使用することをお勧めします。

class Concrete {
    public static function Factory() {
        $rebar = Rebar::Factory();
        $asphalt = Asphalt::Factory();
        $sand = Sand::Factory();

        return new Concrete($rebar, $asphalt, $sand);
    }

    public function __construct(IRebar $rebar, IAsphalt $asphalt, ISand $sand) {
        $this->Rebar = $rebar;
        $this->Asphalt = $asphalt;
        $this->Sand = $sand;
    }
}

IRebarIAsphaltおよびISandはインターフェイス ( http://php.net/manual/en/language.oop5.interfaces.php ) である可能性があります。

interface IRebar {

}

class MyRebar implements IRebar {
}
于 2013-01-22T17:44:22.850 に答える