web-dev-qa-db-ja.com

デザインパターン:抽象ファクトリー対ファクトリーメソッド

注:質問は投稿の最後にあります。

Abstract Factory vs Factory Methodに関する他のstackoverflowスレッドを読みました。各パターンの意図を理解しています。ただし、その定義については明確ではありません。

ファクトリメソッドは、オブジェクトを作成するためのインターフェイスを定義しますが、サブクラスでインスタンス化するものを決定できます。ファクトリメソッドを使用すると、クラスはインスタンス化をサブクラスに委ねることができます。

対照的に、Abstract Factoryは、具象クラスを指定せずに関連オブジェクトまたは依存オブジェクトのファミリーを作成するためのインターフェースを提供します。

- ジョン・フェミネラ

Abstract Factoryは、Factory Methodと非常によく似ています。私のポイントを説明するために、いくつかのUMLクラスを作成しました。

注意:

  • 図はwww.yuml.comからのものであるため、完全に方向付けられていません。しかし、その無料サービス:)。
  • 図は完全ではないかもしれません。私はまだGoFの設計パターンを学んでいます。

工場メソッド:

Factory Method

Abstract Factory(1メンバーのみ):

Abstract Factory (only 1 member)

Abstract Factory(他のメンバー):

alt text

質問:

  1. Abstract Factoryに作成者と製品が1つしかない場合でも、Abstract Factoryパターン? (家族を作成するためのインターフェース)
  2. Factory Method具象クリエーターをインターフェースから作成できますか、またはクラスから作成する必要がありますか? (クラスはインスタンス化をサブクラスに委ねる)
  3. 抽象ファクトリーに作成できるクリエーターと製品が1つだけの場合、Abstract Factory前者の作成者がインターフェイスであり、後者の作成者がクラスであるファクトリメソッド
141
user295190

お役に立てれば。さまざまなタイプの工場について説明します。参照として Head First Design Patterns を使用しました。 yuml.me を使用して図を作成しました。

静的ファクトリー

製品のさまざまなサブタイプを生成する静的メソッドを持つクラスです。

Static Factory

シンプルファクトリー

製品のさまざまなサブタイプを生成できるクラスです。 (Static Factoryよりも優れています。新しいタイプが追加された場合、基本ProductクラスはSimple Factoryクラスのみを変更する必要はありません)

Simple Factoryt

ファクトリーメソッド

タイプに関連する1つのタイプの製品を生成する1つのメソッドが含まれます。 (タイプはサブクラスに委ねられるため、シンプルファクトリよりも優れています。)

Factory Method

Abstract Factory

関連するタイプのファミリーを生成します。生成する型のメソッドが複数あるため、ファクトリメソッドとは著しく異なります。 (これは複雑です。実際の例については、次の図を参照してください)。

Abstract Factory

.NET Frameworkの例

DbFactoriesProviderはサブタイプがないため、シンプルファクトリです。 DbFactoryProviderは、接続オブジェクトやコマンドオブジェクトなどのさまざまな関連データベースオブジェクトを作成できるため、抽象ファクトリーです。

Abstract Factory From .NET Framework 

133
user295190

2つのパターンは確かに関連しています!

パターンの違いは一般に意図です。

intentofFactory Methodは、「オブジェクトを作成するためのインターフェースを定義する、ただし、サブクラスがインスタンス化するクラスを決定できるようにします。FactoryMethodを使用すると、クラスはインスタンス化をサブクラスに延期できます。」

intentofAbstract Factoryは、「具象クラスを指定せずに、関連オブジェクトまたは依存オブジェクト。」

純粋にこれらの意図ステートメント(GoFから引用)に基づいて、確かにFactory Methodは何らかの意味で「縮退」Abstract Factoryと1つのファミリ。

Factory Methodは、Abstract Factory

ただし、それらは実装にも関連しています。 GoFブックに記載されているように、

AbstractFactoryは、製品を作成するためのインターフェースのみを宣言します。実際に作成するのは、ConcreteProductサブクラス次第です。これを行う最も一般的な方法は、各製品のファクトリメソッドを定義することです。

この c2 wiki には、このトピックに関する興味深い議論もあります。

78
Don Roby

OPの(優秀な)質問のリストは無視されているようです。現在の答えは、単に再定義された定義を提供するだけです。したがって、元の質問に簡潔に対処しようとします。

  1. Abstract Factoryに作成者と製品が1つしかない場合でも、Abstract Factoryパターンですか? (家族を作成するためのインターフェース)

いいえ。 Abstract Factorymustは、「関連製品のファミリ」を作成するために複数の製品を作成します。正規のGoFの例では、ScrollBar()およびWindow()を作成します。利点(および目的)は、Abstract Factoryが複数の製品に共通のテーマを適用できることです。

  1. Factory Method具体的なクリエーターをインターフェイスから作成できますか、またはクラスから作成する必要がありますか? (クラスはインスタンス化をサブクラスに延期します)

まず、GoFが本を書いたときにJavaもC#も存在しなかったことに注意する必要があります。 GoFでの用語interfaceの使用は、特定の言語で導入されたインターフェイスタイプとは無関係です。したがって、具象クリエーターは任意のAPIから作成できます。パターンの重要な点は、APIが独自のファクトリメソッドを使用するため、1つのメソッドのみを含むインターフェイスは、抽象ファクトリである以上ファクトリーメソッドになれないことです。

  1. Abstract Factoryに作成できるのは1つのクリエーターと1つの製品のみである場合、Abstract FactoryFactory Methodの唯一の違いは、前者のクリエーターがインターフェイスであり、後者の作成者はクラスですか?

上記の回答に従って、この質問は無効になりました。ただし、Abstract FactoryとFactory Methodの唯一の違いが作成される製品の数だと考えている場合は、クライアントがこれらの各パターンをどのように消費するかを検討してください。通常、抽象ファクトリはクライアントに挿入され、構成/委任を介して呼び出されます。ファクトリメソッドを継承する必要があります。したがって、すべて古い構成と継承の議論に戻ります。

しかし、これらの答えは4番目の質問を提起しました!

  1. なぜなら、メソッドが1つだけのインターフェースはFactory MethodになることはできませんAbstract Factoryメソッドを1つだけ使用して、作成インターフェイスとは何を呼びますか?

メソッドが静的な場合、一般的にStatic Factoryと呼ばれます。メソッドが静的でない場合、一般的にSimple Factoryと呼ばれます。これらはどちらもGoFパターンではありませんが、実際にははるかに一般的に使用されています!

13
jaco0646

私の意見では、2つのパターンのわずかな違いは適用可能性にあり、すでに述べたようにIntentにあります。

定義を復習しましょう(両方ともWikipediaから)。

抽象的な工場

具体的なクラスを指定せずに、関連オブジェクトまたは依存オブジェクトのファミリーを作成のインターフェースを提供します。

工場メソッド

オブジェクトを作成するためのインターフェイスを定義しますが、インターフェイスを実装するクラスがインスタンス化するクラスを決定するを定義します。 Factoryメソッドを使用すると、クラスはインスタンス化をサブクラスに延期できます。

どちらのパターンでも、ユーザーオブジェクトを必要なインスタンスの作成から切り離すことができ(実行時の切り離し)、これが一般的な側面です。どちらのパターンでも、特定のニーズに応じて工場の階層を作成できます。これは別の一般的な側面です。

Abstract Factoryを使用すると、1つのサブクラスで複数の異なるタイプのインスタンスを作成し、異なるサブクラスで作成動作を具体化できます。通常、Factoryメソッドは、サブクラス化メカニズムに従って特定化できるオブジェクトの1つのタイプのみの作成を宣言します。それが違いです。

要約することにより。 Productが作成オブジェクトのスーパークラスを定義し、ProductAとProductBが2つの異なるサブクラスであるとしましょう。したがって、Abstract Factoryメソッドには、createProductA()とcreateProductB()の2つのメソッドがあり、特定のサブクラスで(作成手順に関して)特定されます。ファクトリサブクラスは作成中のオブジェクトの2つの定義されたクラスの作成手順

上記の例によると、ファクトリメソッドは異なる方法で実装され、多くの工場でProductAとProductBの作成を抽象化し(ファクトリごとに1つのメソッド)、さらに作成ステップの特殊化を行いますは、構築時に階層に委任されます。

4
Paolo Maresca

抽象化された(インターフェイスまたは抽象基本クラスを介して参照)を作成した場合オブジェクトを作成するメソッドが1つしかないオブジェクトを作成するファクトリクラスFactory Methodである。

抽象化されたFactoryにオブジェクトを作成するためのメソッドが複数ある場合、Abstract Factoryになります。

MVCコントローラーのアクションメソッドのニーズを処理するマネージャーを作成するとします。ビューモデルの作成に使用されるエンジンオブジェクトを作成するなど、1つのメソッドがある場合は、ファクトリメソッドパターンになります。一方、ビューモデルエンジンを作成するメソッドとアクションモデルエンジン(またはアクションメソッドにコンシューマーが含まれるモデルを呼び出すもの)を作成するメソッドの2つのメソッドがある場合、それは抽象ファクトリーになります。

public ActionResult DoSomething(SpecificActionModel model)
{
    var actionModelEngine = manager.GetActionModelEngine<SpecificActionModel>();
    actionModelEngine.Execute(SpecificActionModelEnum.Value);

    var viewModelEngine = manager.GetViewModelEngine<SpecificViewModel>();
    return View(viewModelEngine.GetViewModel(SpecificViewModelEnum.Value);
}

StackOverflowの人々が他の投稿でも同様にこの問題について質問してから(長年2009年になりますが)、私はまだ望んでいた答えを見つけることができませんでした。


そこで、Webで数時間調査し、例をレビューし、この結論に至りました。AbstractFactoryとFactory Methodの主な違いは次のとおりです。

  • 意図:コヒーレンスまたは「ルックアンドフィール」:Abstract Factoryの意図は、同じスタイル(たとえば、同じルックアンドフィールUIウィジェット、同じスタイルの自動車部品)のオブジェクトファミリをグループ化することです。 、同じOSのオブジェクトなど)。AbstractFactoryの多くの例では、キーフレーズ「同じルックアンドフィール」について言及しています。
  • より大きなグループオブジェクトを形成するオブジェクト:Abstract Factoryは、単一のオブジェクトではなく、より大きなグループオブジェクトを形成する一連のオブジェクトを作成します。
  • 後で新しいスタイルを追加:Factory Methodを使用し続け、既存のインフラストラクチャに新しいスタイルのセットを追加しようとすると、苦労します。 Abstract Factoryを使用すると、抽象ファクトリクラスを実装する新しい具体的なファクトリを作成するだけで済みます。

反例は

  • セダンで使用されるスポーツカー用の自動車部品。この矛盾は事故につながる可能性があります。
  • さまざまなOS GUIウィジェットのWindowsスタイルのボタン。それは何も壊さないが、私のような一部の人々にとってユーザー体験を損なうだろう。
  • 後で、ソフトウェアの下位互換性を維持しながら、互換性のあるさまざまなシステムオブジェクトのセットを必要とする次のOSアップグレードでソフトウェアを実行する必要があることがわかりました。

したがって、最終的なオブジェクトグループが同じスタイルを持つ必要がある場合例外なしで、この「同じスタイルを維持する」詳細を非表示にする場合は、Abstract Factoryを使用する必要があります。

1
Andrew Chong
/*
//Factory methods:

//1. Factory Method - Abstract Creator Class



#include <iostream>
#include <string.h>
using namespace std;

const std::string nineNintyCC = std::string("990CC");
const std::string thousandTwoHundredCC = std::string("1200CC");
const std::string ThousandFiveHundredCC = std::string("1500CC");
const std::string fiveThousandCC = std::string("5000CC");

// Product
class Engine
{
    public:
    virtual void packEngine() = 0;  
};

// Concrete products
// concrete product class one
class C990CCEngine: public Engine
{

    public:
    void packEngine()
    {
       cout << "Pack 990CC engine" << endl;   
    }
};

// concrete class Two
class C1200CCEngine: public Engine
{   public:
    void packEngine()
    {
        cout << "pack 1200CC engine" << endl;
    }

};

// Concrete class Three
class C1500CCEngine: public Engine
{
    public:
    void packEngine()
    {
        cout << "Pack 1500CC engine" << endl;
    }

};


// Car Factory:
class CarFactory{
    public:

    virtual Engine* createEngine(const std::string& type) = 0;
};
class Factory: public CarFactory
{
    public:
     Engine *createEngine(const std::string& type)
     {

          if(0 == nineNintyCC.compare(type))
          {    
             return new C990CCEngine;
          }
          else if(0 == thousandTwoHundredCC.compare(type))
          {
             return new C1200CCEngine;
          }
          else if(0 == ThousandFiveHundredCC.compare(type))
          {
             return new C1500CCEngine;
          } 
          else
           {
                 cout << "Invalid factory input" << endl;
             return NULL;
           }
           return NULL;
     }
};

int main()
{

    CarFactory* ptr = new Factory;
    Engine*pEngine =  ptr->createEngine(nineNintyCC);
    if(pEngine)
    {
        pEngine->packEngine();
        delete pEngine;
    }
    else
    {
        cout << "No engine exists of your type in our factory" << endl;
    }
    pEngine =  ptr->createEngine(ThousandFiveHundredCC);
    if(pEngine)
    {
        pEngine->packEngine();
        delete pEngine;
    }
    else
    {
        cout << "No engine exists of your type in our factory" << endl;
    }
    pEngine =  ptr->createEngine(thousandTwoHundredCC);
    if(pEngine)
    {
        pEngine->packEngine();
        delete pEngine;
    }
    else
    {
        cout << "No engine exists of your type in our factory" << endl;
    }
    pEngine = ptr-> createEngine(fiveThousandCC);
    if(pEngine)
    {
        pEngine->packEngine();
        delete pEngine;
    }
    else
    {
        cout << "No engine exists of your type in our factory" << endl;
    }
    return 0;
}

*/
/*
//
// interface product
#include <iostream>
#include <string>
using namespace std;

class Engine
{
 public:
 virtual void EngineType() = 0;

};

// concrte product
class AltoEngine: public Engine
{
  public:
  void EngineType()
  {
      cout << "Alto Engine" << endl;
  }
};

//Concrte product
class SwiftEngine : public Engine
{
    public:
    void EngineType()
    {
        cout << "Swift Engine" << endl;    
    }
};

class Body
{
   public:
    virtual void bodyType() = 0;

};

class AltoBody: public Body
{
  public:  
    virtual void bodyType()
    {
        cout << "Alto Car Body" << endl;
    }
};

class SwiftBody : public Body
{
    public:
    void bodyType()
    {
        cout << "SwiftCar Body" << endl;
    }

};


class CarFactory
{
   public:
   virtual Engine* createEngineProduct() = 0;
   virtual Body*   createBodyPoduct() = 0;
};
class AltoCarFactory: public CarFactory
{
    public:
    Engine * createEngineProduct()
    {
        return new AltoEngine;
    }
    Body* createBodyPoduct()
    {
        return new AltoBody;
    }

};

class SwiftCarFactory: public CarFactory
{
    public:
    Engine * createEngineProduct()
    {
        return new SwiftEngine;
    }
    Body* createBodyPoduct()
    {
        return new SwiftBody;
    }

};

int main()
{

    CarFactory* pAltoFactory = new AltoCarFactory;
    Engine* pAltoEngine = pAltoFactory->createEngineProduct();
    pAltoEngine->EngineType();
    Body* pAltoBody = pAltoFactory->createBodyPoduct();
    pAltoBody->bodyType();



    CarFactory* pSwiftFactory = NULL;
    pSwiftFactory = new SwiftCarFactory;
    Engine* pSwiftEngine = pSwiftFactory->createEngineProduct();
    pSwiftEngine->EngineType();
    Body* pSwfitBody = pSwiftFactory->createBodyPoduct();
    pSwfitBody->bodyType();
    delete pAltoBody;
    delete pAltoFactory;
    delete pSwfitBody;
    delete pSwiftFactory;
    return 0;
}
*/

/*

// One more Factory example;

#include <iostream>
#include <string>
using namespace std;

const std::string maruthi = std::string("Maruthi");
const std::string fiat = std::string("Fiat");
const std::string renault = std::string("Renault");
// Interface
class CarEngine
{
 public:
    virtual void engineType() = 0;
};

// Concrete class
class FiatEngine: public CarEngine
{
  public:
  void engineType()
  {
      cout << "Fait Engine Engine" << endl;
  }

};
// ConcreteClass
class RenaultEngine : public CarEngine
{
    public:
    void engineType()
    {
        cout << "Renault Engine" << endl;
    }

};
// Concrete class
class MaruthiEngine : public CarEngine
{
    public:
    void engineType()
    {
        cout << "Maruthi Engine" << endl;
    }
};


// Factory
class CarFactory
{
    public:
    virtual CarEngine* createFactory(const std::string&) = 0;
};

// EngineFactory
class CarEngineFactory : public CarFactory
{
     public:
     CarEngine* createFactory(const std::string&  type)
     {
          if(0 == maruthi.compare(type))
          {
              return new MaruthiEngine;

          }
          else if(0 == fiat.compare(type))
          {
              return  new FiatEngine;
          }
          else if(0 == renault.compare(type))
          {
              return new RenaultEngine;
          }
          else
          {
              cout << "Invalid Engine type" << endl;
              return NULL;
          }
     }

  };

int main()
{
    CarFactory* pCarFactory = new CarEngineFactory;
    CarEngine* pMaruthiCarEngine = pCarFactory->createFactory(maruthi);
    pMaruthiCarEngine->engineType();

    CarEngine* pFiatCarEngine = pCarFactory->createFactory(fiat);
    pFiatCarEngine->engineType();


    CarEngine* pRenaultCarEngine = pCarFactory->createFactory(renault);
    pRenaultCarEngine->engineType();

    return 0;
}


*/


/*

// One more Factory example;

#include <iostream>
#include <string>
using namespace std;

const std::string maruthi = std::string("Maruthi");
const std::string fiat = std::string("Fiat");
const std::string renault = std::string("Renault");


// Interface
class CarEngine
{
 public:
    virtual void engineType() = 0;
};

// Concrete class
class FiatEngine: public CarEngine
{
  public:
  void engineType()
  {
      cout << "Fait Car Engine" << endl;
  }

};

// ConcreteClass
class RenaultEngine : public CarEngine
{
    public:
    void engineType()
    {
        cout << "Renault Car Engine" << endl;
    }

};

// Concrete class
class MaruthiEngine : public CarEngine
{
    public:
    void engineType()
    {
        cout << "Maruthi Car Engine" << endl;
    }
};

// Interface
class CarBody
{
 public:
    virtual void bodyType() = 0;
};

// Concrete class
class FiatBody: public CarBody
{
  public:
  void bodyType()
  {
      cout << "Fait car Body" << endl;
  }

};

// ConcreteClass
class RenaultBody : public CarBody
{
    public:
    void bodyType()
    {
        cout << "Renault Body" << endl;
    }

};

// Concrete class
class MaruthiBody : public CarBody
{
    public:
    void bodyType()
    {
        cout << "Maruthi body" << endl;
    }
};


// Factory
class CarFactory
{
    public:
    virtual CarEngine* createCarEngineProduct() = 0;
    virtual CarBody* createCarBodyProduct() = 0;
};

// FiatFactory
class FaitCarFactory : public CarFactory
{
     public:
     CarEngine* createCarEngineProduct()
     {
        return new FiatEngine; 
     }
     CarBody* createCarBodyProduct()
     {
         return new FiatBody;
     }
};

// Maruthi Factory
class MaruthiCarFactory : public CarFactory
{
     public:
     CarEngine* createCarEngineProduct()
     {
         return new MaruthiEngine;
     }
     CarBody* createCarBodyProduct()
     {
         return new MaruthiBody;
     }

};

// Renault Factory
class RenaultCarFactory : public CarFactory
{
     public:
    CarEngine* createCarEngineProduct()
    {
        return new RenaultEngine;
    }

    CarBody* createCarBodyProduct()
    {
        return new RenaultBody;
    }

};


int main()
{

   // Fiat Factory
   CarFactory* pFiatCarFactory = new FaitCarFactory;
   CarEngine* pFiatEngine = pFiatCarFactory->createCarEngineProduct();
   CarBody*  pFiatBody = pFiatCarFactory->createCarBodyProduct();
   pFiatEngine->engineType();
   pFiatBody->bodyType();

   // Renault Car Factory
    return 0;
}

*/

抽象ファクトリおよびファクトリメソッド定義の意味を理解している限り、最初の定義は静的コンテキストで実装され、入力パラメータに基づいてオブジェクトを提供します。

2つ目は、ファクトリメソッドインターフェイスを実装する既に作成されたオブジェクト(ファミリ)を使用します。次に、ファクトリメソッドは、元のオブジェクトに関係なく特定のインスタンスを作成します。

そのため、通常、両方のパターンを一緒に使用して、最初のステップで関連オブジェクトのファミリーを記述する一般的なオブジェクトを作成します。静的メソッドgetInstance( "my family name")メソッドによって呼び出されます。このようなgetInstanceメソッドの実装により、作成されるファミリオブジェクトが決定されます。

次に、新しく作成されたファミリオブジェクトでcreateProduct()メソッドを呼び出します。ファミリオブジェクトに応じて、新しい製品が返されます。

これらのパターンはそれぞれに協力しているようです。

言い換えると、Abstract Factoryは「WHAT」が作成され、Factoryメソッド「HOW」が作成されることに焦点を当てています。

0
Jan Stanicek

ファクトリメソッドパターンは、作成中のオブジェクトの正確なクラスを表示せずにオブジェクトの作成を処理する作成デザインパターンです。この設計パターンにより、基本的に、クラスはインスタンス化をサブクラスに延期できます。

Abstract Factoryパターンは、具体的なクラスを公開せずに個々の工場のグループにカプセル化を提供します。このモデルでは、抽象ファクトリクラスの汎用インターフェイスを使用して、オブジェクトの実装の詳細を使用法や構成から分離する必要な具体的なオブジェクトを作成します。この設計パターンは、同様の種類のGUIコンポーネントを作成する必要があるGUIアプリケーションで広く使用されています。

グーグルで検索している間、私は両方のデザインパターンを見事に説明したブログに従って来ました。これらを見てください

http://simpletechtalks.com/factory-design-pattern/

http://simpletechtalks.com/abstract-factory-design-pattern/

0
Neo

覚えておかなければならないのは、抽象ファクトリーが複数のファクトリーを返すことができるファクトリーであることです。したがって、AnimalSpeciesFactoryがある場合、次のようなファクトリーを返すことができます。

Mamalfactory、BirdFactory、Fishfactory、ReptileFactory。 AnimalSpeciesFactoryから単一のファクトリーを取得したので、ファクトリーパターンを使用して特定のobjextを作成します。たとえば、このAnimalFactoryからReptileFactoryを取得し、ヘビ、カメ、トカゲオブジェクトのような爬虫類オブジェクトの作成を提案できるとします。

0
j2emanue