2011-04-14 7 views
5

私は、PHPでファクトリパターンを実装する2つの異なる方法のうちの1つを考えています。私は、これらのバリアントが適切な名前を持っているかどうかわかりません。だから私はそれらを内部工場と外部工場と呼ぶつもりです。内部対外部の工場

内部ファクトリ:ファクトリメソッドは静的パブリックメソッドとしてクラス自体に実装され

<?php 
class Foo 
{ 
    protected 
     $loadedProps = false; 

    public static factory ($id) 
    { 
     $class = get_called_class(); 
     $item = new $class ($id); 
     if ($item -> loadedProps()) 
     { 
      return ($item); 
     } 
    } 

    public function loadedProps() 
    { 
     return ($this -> loadedProps); 
    } 

    protected function loadPropsFromDB ($id) 
    { 
     // Some SQL logic goes here 
    } 

    protected function __construct ($id) 
    { 
     $this -> loadedProps = $this -> loadPropsFromDB ($id); 
    } 
} 
?> 

外部工場:工場、それが初期化する項目は別個のエンティティとして実装さ

<?php 

class Foo 
{ 
    protected 
     $loadedProps = false; 

    public function loadedProps() 
    { 
     return ($this -> loadedProps); 
    } 

    protected function loadPropsFromDB ($id) 
    { 
     // Some SQL logic goes here 
    } 

    public function __construct ($id) 
    { 
     $this -> loadedProps = $this -> loadPropsFromDB ($id); 
    } 
} 

abstract class FooFactory 
{ 
    public static factory ($id) 
    { 
     $item = new Foo ($id); 
     if ($item -> loadedProps()) 
     { 
      return ($item); 
     } 
    } 
} 
?> 

今はそれぞれがそのメリットを持っているようです。

前者では、外部からコンストラクタを非表示にすることができます。つまり、Fooオブジェクトを作成する唯一の方法は、工場を経由することです。アイテムの状態をDBからロードできない場合、ファクトリはNULLを返します。このNULLはコードで簡単に確認できます。

if ($item = Foo::factory ($id)) 
{ 
    // ... 
} 
else 
{ 
    // The item failed to load. Handle error here 
} 

工場は、変更を加えずにFooの任意のサブクラスのオブジェクトを作成することもできます。

ただし、いくつかの欠点があるようです。まずクラスはファクトリを実装しなければなりません。ファクトリは実際に他のクラスに属するクラスに責任を負わせるかもしれません。内部の工場のバージョンは、確かに外部の工場のバージョンよりも大きなクラスになります。

外部の工場については、工場はクラスそのものではないので、きれいだし、もっと責任を負うクラスについて心配する必要はありません。外部ファクトリは依存性注入により適しています。

ただし、独自の欠点があります。まず第一に、PHPがパッケージの概念を持たず、クラスメンバのための「パッケージ」保護レベルもないため、工場で構築されるアイテムのコンストラクタはpublicでなければなりません。つまり、新しいFoo()を実行して工場をバイパスするだけで、コーダーが停止することはありません(ユニットテストは簡単になります)。

もう1つの問題は、FooFactoryはFooオブジェクトのみを作成でき、サブクラスは作成できないことです。これはFooFactoryに別のパラメータを追加してクラス名を指定することで回避できますが、工場では指定されたオブジェクトクラスがFooの子孫であるという内部チェックを行う必要があります。

基本的に、2つのアプローチの相対的なメリットは何ですか?どのようなものをお勧めしますか?

また、社内外の工場よりも固有の名前がある場合は、それらを知りたいと思います。

答えて

7

あなたはGoFの書籍やSourcemaking:

  • 抽象ファクトリーで、その目的について読むことができるように実際には、工場は、生成に関するデザインパターンを確立している - クラス
  • のいくつかの家族のインスタンスを作成します。ビルダー - オブジェクトの構成をその表現から分離する
  • 工場メソッド - いくつかの派生クラスのインスタンスを作成する
  • オブジェクトプール - 使用されなくなったオブジェクトのリサイクルすることにより、高価な買収や資源の放出を避ける
  • プロトタイプは- 完全に初期化されたインスタンスをコピーまたはクローン化するために

いくつかの重複がありますこれらのパターンでは、特にファクトリメソッド、抽象ファクトリ、ビルダーの間にあり、オブジェクトのファミリを作成していないときは区別がさらにぼやけますが、オブジェクトの種類は1つだけです。ですから、簡単にするために、社内外の工場が正しい条件であるとしましょう。

個人的に、私はいつもあなたが既に与えた理由のために、内部工場よりも外部工場を好むでしょう:私はDependency Injectionを使うことができ、separate the responsibilitiesを使うことができます。 static methods are death to testability以降、彼らが導入するカップリングのためにconsidered harmfulになる可能性がありますが、代わりにFactoryを実際のオブジェクトにして、非静的メソッドを使用します。

あなたが言及する2つの欠点は、本当に欠点ではありません。

prevent a developerは、Factoryが作成するオブジェクトをインスタンス化しないようにする理由が考えられません。実際には、Unit-Testing私は自分自身でそのオブジェクトを作成し、どんな依存関係もMocks and Stubsに置き換えたいと思うでしょう。 I also dont believe that developers should be babysitted too much。 PHPのスクリプトの性質を考えると、ctorをprivateからpublicに変更することは、あまりにも簡単に効果的に防止できます。

ファクトリが他のクラスを作成できないという別の問題については、それは当てはまりません。ファクトリのアイデアは、実際にはさまざまなタイプのオブジェクトファミリを作成することです。 Factoryメソッドでさえ明示的にサブクラスを作成することができます。スイッチ/ケースを使用して実装するか、工場でさまざまな方法を実装するかは、あなた次第です。また、ファクトリとビルダーを組み合わせたり、ファクトリオブファクトリを持たずにオブジェクトを作成するロジックをカプセル化したりする理由もありません。したがって、あなたが言及した内部チェックの必要性を排除します(これはタイプヒントでも満たされる可能性があります)。

工場のもう1つの実行可能な代替方法は、Symfony Components DICのようにDependency Injection Containerを使用し、そのコンテナを通じてオブジェクトを管理することです。

+0

「オフトピック:」ランダムなメモでは、同じユーザー名を持つときに、両方とも同じことを話していることがユーモラスなことが分かります。もう一度私はあなたと話していると思った。 – Tek

+0

@Tekええ、ゴードンはゴードンに答える。しかし、私はGordon™です:) – Gordon

関連する問題