2016-04-22 8 views
1

私は、渡される列挙型に基づいて異なる具体的な型を返すファクトリクラスを構築する必要があるユースケースを持っています。しかし、これらの型のそれぞれは、異なるコンストラクタパラメータを必要とします。だから、その場合、異なる署名を持つ複数のメソッドを持つことは理にかなっているのでしょうか、それとも全く工場のパターンではありませんか?ファクトリメソッドのパターンで異なるオーバーロードを使用することができます

私は

class CarFactory 
{ 
    public ModelS TeslaMaker (List<Battery> batteries){/*return ModelS*/} 
    public Mustang FordMaker (Engine engine) {/*return a Mustang*/} 
} 

代わりの

class CarFactory 
    { 
     public Car GetCar(CarType carType) //where CarType is an enum (Ford=0,Tesla=1) 
     { 
     switch(carType) 
     { case CarType.Ford: return new Mustang(); }//just an example 
     } 
    } 

EDIT言うようなものと思っています。私の場合、私は実際にクラスの家族を返す必要が を。したがって、テスラの場合は、ModelS、ModelSService、ModelSWarrantyなどを返します。そこで、ここで与えられた提案をラップする抽象ファクトリのアプローチに進むつもりです。

+0

最初のものは実際に列挙部分を持っていませんが、 – Nyerguds

+0

@ニーアードゥーズ - はい、それが工場のパターンであったとしても疑いはありませんでした。 – arviman

答えて

0

はい、工場出荷時のパターンです。 ファクトリパターンは、オブジェクトのファクトリを作成することを指示しますが、サブクラスでオブジェクトをインスタンス化する方法を決定させます。 あなたのケースではEnumのタイプに基づいて決定することになります

2

いいえ、それは因子パターンの良い例ではありません。 Carクラスが異なるタイプのコンポーネントに依存している場合でも、それらのファクトリを持つことができます。 EGのために車とエンジンのあなたのようなことができます:あなたは別の間で選択できるオブジェクトを作成するための異なるパラメータ(フォード用テスラやエンジン用電池)を必要とする場合には

public interface ICar 
    { 
     IEngine Engine { get; set; } 
    } 

    public class Mustang : ICar 
    { 
     private IEngine _engine = EngineFactory.GetEngine(EngineType.Mustang); 
     public IEngine Engine 
     { 
      get { return _engine; } 
      set { _engine = value; } 
     } 
    } 

    public class CarFactory 
    { 
     public ICar GetCar(CarType carType) 
     { 
      switch (carType) 
      { case CarType.Ford: return new Mustang(); } 
     } 
    } 
エンジン

ための同様

public interface IEngine { } 

    public class MustangEngine : IEngine 
    { 

    } 

    public class EngineFactory 
    { 

     public static IEngine GetEngine(EngineType engine) 
     { 
      switch (engine) 
      { case EngineType.Mustang: return new MustangEngine(); } 
     } 
    } 
+0

はい、作成するオブジェクトのファミリを持っているので、私の場合は抽象ファクトリを使用するように見えます。 – arviman

2

をソリューション: - ファクトリを作成している間にこれらのパラメータをすべて渡します。このような詳細を持つすべてのタイプの車に特定の工場があります。

class SpecificCarFactory 
{ 
    public SpecificCarFactory(IList<Battery> batteries, IList<Engine> engines) 
    { 
    //save batteries etc into local properties 
    } 
    public Car GetCar(CarType carType) 
    { 
    switch(carType) 
    { case CarType.Ford: return new Mustang(_engines.First()); } 
    } 
} 
  • クラスオブジェクトにパラメータをカプセル化し、ファクトリメソッドのパラメータからそれらを取得します。

    class CarFactory 
    { 
         public Car GetCar(CarDetail carDetail) //where CarDetails     encapsulates all the possible car details 
         { 
          switch(carDetail.type) 
          { case CarType.Ford: return new Mustang(carDetail.Engine);//just an example 
          } 
         } 
    } 
    
+0

カプセル化は良いですが、それぞれのタイプが異なるパラメータを必要とするので、忘れてはならないステップが1つあります:渡されたオブジェクトに定義されたパラメータをチェックしてください(あなたが 'NullReferenceException'の奇跡のレシピではない場合) – Sidewinder94

+0

OfアサーションまたはCodeContractsフレームワークを使用して行う必要があります。 – VitaliyK

+0

私はこれについて最初に考えましたが、パラメータのサブセットのみが必要なときには、すべてを回っていくのがちょっと難しいと判断しました。 – arviman

4

ので、その場合には、異なるシグネチャを持つ複数のメソッドを持ってしても意味が、あるいはすべての工場出荷時のパターンそれはないでしょうか?

特定の方法で工場を構えることは意味がありません。クライアントコードでどの特定のメソッドを使用するかを決める必要がある場合、なぜ特定のcarのコンストラクタを直接呼び出さないのでしょうか?あなたの例では、ファクトリメソッドは単に特定のコンストラクタ上のラッパーにすぎません。

一方、列挙型で呼び出される単一のファクトリメソッドを使用すると、クライアントはどの車を作成すべきかを動的に決定する機会が与えられます。たとえば、データベースクエリに基づいて決定できます。

現在のアプローチにはいくつかの方法があります。

1つのオプションは、コンストラクタパラメータを表すクラスの階層を持つことです。

public abstract class CarCreationParams { } 

public class FordCreationParams : CarCreationParams 
{ 
    public Engine engine; 
} 

... 

public class CarFactory 
{ 
    public Car GetCar(CarCreationParams parms) 
    { 
     if (parms is FordCreationParams) 
      return new Ford(((FordCreationParams)parms).engine); 
     ... 

別のオプションは、あなたが本当に外部で作成するためにあなたのフォードが必要かどうかを考えるのは次のようになります。パラメータの型を作成する必要があり、特定のどの車を推測するのに十分であるので、あなたも、その後、列挙型を必要としませんエンジン(集約)ではなく、エンジン(構成)を所有しています。後者の場合、パラメータのないコンストラクタを特定の車種に公開することになります。

public class Ford : Car 
{ 
    public Engine engine; 

    // car is composed of multiple parts, including the engine 
    public Ford() 
    { 
      this.engine = new FordEngine(); 
    } 

これにより、工場の実装がはるかに簡単になります。

+0

ありがとうございます。これは素晴らしい答えです。あなたが作曲で言ったようにそれを実装することもできます。しかし、Dependence Injectionコンテナをファクトリメソッドに渡してオブジェクトを返すのではなく、DIコンテナの上に置くことを考えていました。これは、1つのオブジェクトだけでなく、ワイヤリングする必要のあるクラスのファミリがあるためです。しかし、それは工場での懸念の原則の分離に反対しているように見えます(なぜDIコンテナについて工場が気にしますか)。だから私は私の場合は "抽象工場"のようなものを使用する必要があると思う。 – arviman

+1

内部的にDIコンテナを使用している可能性のある工場の実装に関するチュートリアルを読むhttp://www.wiktorzychla.com/2016/01/di-factories-and-composition-root.html –

+0

実際にチュートリアルでDIを外部で使用していますクライアント側で私は同じことをやろうとしていますが、私はDIを工場の内部に参照パラメータとして渡すことを考えていました。そのため、工場は具象クラスを返す代わりにDIコンテナを補強します。 – arviman

関連する問題