抽象ファクトリーとファクトリーデザインパターンの違いは何ですか?


454

これら2つのパターンの違いについては多くの投稿があることは知っていますが、見つけられないことがいくつかあります。

私が読んでいることから、ファクトリメソッドパターンを使用すると、単一の具体的な製品を作成する方法を定義できますが、一般的な製品を表示するため、クライアントから実装を隠すことができます。私の最初の質問は、抽象ファクトリーについてです。その役割は、単一のコンクリートオブジェクトだけでなく、使用する具体的なファクトリに依存するコンクリートオブジェクトのファミリを作成できるようにすることですか?抽象ファクトリーは、呼び出すメソッドに応じて、非常に大きなオブジェクトを1つだけ返すのか、それとも多くのオブジェクトを返すのですか?

私の最後の2つの質問は、私が多くの場所で見たことを完全には理解できない単一の引用に関するものです。

2つの違いの1つは、抽象ファクトリパターンでは、クラスがオブジェクトのインスタンス化の責任を合成によって別のオブジェクトに委譲するのに対し、ファクトリメソッドパターンは継承を使用し、サブクラスに依存して目的のオブジェクトのインスタンス化を処理することです。

私の理解では、ファクトリー・メソッド・パターンにはCreatorインターフェースがあり、これにより、具象化するConcreteProductを、ConcreteCreatorが管理できるようになります。これは、継承を使用してオブジェクトのインスタンス化を処理することの意味ですか?

さて、その引用に関して、抽象ファクトリパターンは、オブジェクトのインスタンス化の責任を、合成を介して別のオブジェクトにどのように委任するのでしょうか。これは何を意味するのでしょうか?抽象ファクトリパターンも、継承を使用して構築プロセスを実行しているように見えますが、やはりこれらのパターンについてはまだ学習しています。

特に最後の質問で何か助けていただければ幸いです。



クライアントの観点から「インスタンスがどのように作成されたか」を見ると、見積もりを理解するのに役立ちます。
Karthik Bose

@nawfal、そのスレッドの答えはひどいです。
jaco0646 2016年

回答:


494

2つの違い

「ファクトリー・メソッド」と「抽象ファクトリー」の主な違いは、ファクトリー・メソッドが単一のメソッドであり、抽象ファクトリーがオブジェクトであることです。多くの人がこれら2つの用語を混同し、同じ意味で使用し始めていると思います。私はそれらを学んだとき、違いが何であるかを正確に見つけるのに苦労したことを覚えています。

ファクトリメソッドは単なるメソッドであるため、サブクラスでオーバーライドできるため、引用の後半は次のようになります。

... Factoryメソッドパターンは継承を使用し、サブクラスに依存して目的のオブジェクトのインスタンス化を処理します。

引用は、オブジェクトがここで独自のファクトリメソッドを呼び出していることを前提としています。したがって、戻り値を変更できるのはサブクラスだけです。

抽象ファクトリは、複数のファクトリメソッドを持つオブジェクトです。見積もりの​​前半を見てください。

...抽象ファクトリパターンを使用すると、クラスはオブジェクトのインスタンス化の責任を構成を介して別のオブジェクトに委任します...

彼らが言っているのは、Fooオブジェクトを作成したいオブジェクトAがあるということです。Fooオブジェクト自体(たとえば、ファクトリメソッドを使用)を作成する代わりに、Fooオブジェクトを作成するために別のオブジェクト(抽象ファクトリ)を取得します。

コード例

違いを示すために、ここでは使用中のファクトリメソッドを示します。

class A {
    public void doSomething() {
        Foo f = makeFoo();
        f.whatever();   
    }

    protected Foo makeFoo() {
        return new RegularFoo();
    }
}

class B extends A {
    protected Foo makeFoo() {
        //subclass is overriding the factory method 
        //to return something different
        return new SpecialFoo();
    }
}

そしてここに使用中の抽象的なファクトリがあります:

class A {
    private Factory factory;

    public A(Factory factory) {
        this.factory = factory;
    }

    public void doSomething() {
        //The concrete class of "f" depends on the concrete class
        //of the factory passed into the constructor. If you provide a
        //different factory, you get a different Foo object.
        Foo f = factory.makeFoo();
        f.whatever();
    }
}

interface Factory {
    Foo makeFoo();
    Bar makeBar();
    Aycufcn makeAmbiguousYetCommonlyUsedFakeClassName();
}

//need to make concrete factories that implement the "Factory" interface here

15
これはとても素晴らしい説明です。しかし、最も重要な部分は何も答えられずに残っています。それは、いつ使用するか、そしていつ他のパターンを使用するかです。
croraf 2014年

11
これが正しいかわかりません。確かに、ファクトリメソッドはファクトリメソッドにちなんで名付けられたデザインパターンですが、クラスの構造と継承が関係しています。これは単一の方法ではありません。
Aviv Cohn 2014年

2
つまり、ファクトリメソッドは、目的の異なるすべての通常のクラスのメソッドである可能性があります。しかし、抽象ファクトリーはクライアントによって使用されるクラス/オブジェクトであり、ファミリーでいくつかの製品を作成することのみに責任がありますか?
Hieu Nguyen 14

「SuperFoo」で「Super」という言葉を使用しているのは、Fooの特殊なケースを意味するだけですか、それとも実際にはスーパークラスを意味しますか?私が想定したように、それはサブクラスでなければなりません。
dahui 2016

@dahuiはい、それはサブクラスです。SpecialFooより明確になるように変更しました。
トムダリング

125

抽象ファクトリは、作成する必要があるオブジェクトのメソッドを定義する抽象メソッドを含む基本クラスを作成します。基本クラスを派生する各ファクトリクラスは、各オブジェクトタイプの独自の実装を作成できます。

ここに画像の説明を入力してください

ファクトリメソッドは、クラス内にオブジェクトを作成するために使用される単純なメソッドです。通常、集約ルートに追加されます(Orderクラスにはと呼ばれるメソッドがありますCreateOrderLine

ここに画像の説明を入力してください

抽象工場

以下の例では、メッセージングシステムからキューの作成を分離できるようにインターフェイスを設計し、コードベースを変更せずにさまざまなキューシステムの実装を作成できるようにします。

interface IMessageQueueFactory
{
  IMessageQueue CreateOutboundQueue(string name);
  IMessageQueue CreateReplyQueue(string name);
}

public class AzureServiceBusQueueFactory : IMessageQueueFactory
{
      IMessageQueue CreateOutboundQueue(string name)
      {
           //init queue
           return new AzureMessageQueue(/*....*/);
      }

      IMessageQueue CreateReplyQueue(string name)
      {
           //init response queue
           return new AzureResponseMessageQueue(/*....*/);
      }

}

public class MsmqFactory : IMessageQueueFactory
{
      IMessageQueue CreateOutboundQueue(string name)
      {
           //init queue
           return new MsmqMessageQueue(/*....*/);
      }

      IMessageQueue CreateReplyQueue(string name)
      {
           //init response queue
           return new MsmqResponseMessageQueue(/*....*/);
      }
}

工場法

HTTPサーバーの問題は、すべての要求に対して常に応答が必要なことです。

public interface IHttpRequest
{
    // .. all other methods ..

    IHttpResponse CreateResponse(int httpStatusCode);
}

ファクトリメソッドがないと、HTTPサーバーユーザー(つまりプログラマー)は、IHttpRequestインターフェイスの目的に反する実装固有のクラスを使用せざるを得ません。

したがって、応答クラスの作成も抽象化されるように、ファクトリメソッドを導入します。

概要

違いは、ファクトリメソッドを含むクラスの目的オブジェクトの作成ではなく、抽象ファクトリはオブジェクトの作成にのみ使用する必要があることです。

オブジェクトを作成するときにLSP(リスコフ置換の原則)を破るのは簡単なので、ファクトリメソッドを使用するときは注意が必要です。


3
なぜ具体的な製品が必要なのですか?
Andrew S

60
誰もアイデアに投資したくないからです。
jgauffin 2016

4
抽象ファクトリーは、単にButton()「関連製品のファミリー」を作るだけではなく、それ以上のものを作成する必要があります。たとえば、標準的なGoFの例ではScrollBar()、およびを作成しWindow()ます。利点は、抽象ファクトリーが複数の製品に共通のテーマを適用できることです。
jaco0646 2016

ハコは正しいです。両方のUML図が本質的に同じであると考えてください(抽象ファクトリUMLが間違っていることを除けば)。どちらの場合でも、クライアントは1つの製品を作成するためのファクトリメソッドを呼び出しています。
コビー2017年

1
@AndrewS:ご質問にお答えします。同じ抽象化(インターフェース)に異なる具体的な製品(クラス)を用意する必要がない場合は、ファクトリパターンではなく、ビルダーパターンが必要になる可能性があります。(決して遅くないよりはましです;))
jgauffin

95

AbstractFactoryとFactoryの設計パターンの違いは次のとおりです。

  • Factoryメソッドは1つの製品の作成にのみ使用されますが、Abstract Factoryは関連または依存する製品のファミリを作成することを目的としています。
  • ファクトリメソッドパターンは、オブジェクトを作成するためのメソッドをクライアントに公開しますが、抽象ファクトリの場合は、これらのファクトリメソッドで構成される可能性のある関連オブジェクトのファミリを公開します。
  • ファクトリメソッドパターンは単一オブジェクトの構築を非表示にするのに対し、抽象ファクトリは関連オブジェクトのファミリの構築を非表示にします。抽象ファクトリは通常、(一連の)ファクトリメソッドを使用して実装されます。
  • 抽象ファクトリパターンは、構成を使用してオブジェクトを作成する責任を別のクラスに委任しますが、ファクトリメソッドデザインパターンは継承を使用し、派生クラスまたはサブクラスに依存してオブジェクトを作成します。
  • ファクトリメソッドパターンの背後にある考え方は、クライアントが実行時に作成する必要がある具体的なクラスを知らない場合でも、抽象ファクトリ パターンが動作しているときに仕事をするクラスを取得したい場合を考慮に入れているということです。システムが複数の製品ファミリを作成する必要がある場合、または実装の詳細を公開せずに製品のライブラリを提供する場合に最適です。

ファクトリメソッドパターンの実装: ファクトリメソッドUML

抽象ファクトリパターンの実装:

抽象ファクトリUML


13
うーん、抽象ファクトリの例についてはわかりません。シェイプファクトリとカラーファクトリは同じメソッドを実装する必要があると思います。しかし、私が正しい場合、サンプルには意味がありません。
Joaquin Iurchuk、2015年

4
箇条書きは正しいです。ただし、両方の図は完全に間違っており、非常に誤解を招きます。抽象ファクトリの正確なモデルについては、@ Tryingの以下の図を参照してください。
jaco0646 2016

1
私は2つの図が実際に非常に誤解を招くことに同意する必要があります。私はtutorialspointのウェブサイトでそれらを見てきましたが、正直言って100%同意しません。説明は良さそうです
SoftwareDeveloper

これは非常に誤解を招くものです。
diyoda_ 2017年

50以上の賛成票と図は非常に間違っています。SOに関する多くの設計パターンの回答を信頼できないことの証明。
Fuhrmanator 2017

27

抽象ファクトリとファクトリメソッドの主な違いは、抽象ファクトリがコンポジションによって実装されることです。ただし、ファクトリメソッドは継承によって実装されます。

はい、あなたはそれを正しく読みました:これらの2つのパターンの主な違いは、古い構成と継承の議論です。

UML図は(GoF)ブックにあります。このスレッドの上位2つの回答の例を組み合わせると、どちらか一方の回答よりも優れたデモンストレーションが得られると思うので、コード例を提供したいと思います。さらに、クラス名とメソッド名にはこの本の用語を使用しています。

抽象ファクトリー

  1. ここで把握する最も重要な点は、抽象ファクトリがクライアントに注入されることです。これが、抽象ファクトリはコンポジションによって実装されると言う理由です。多くの場合、依存関係注入フレームワークがそのタスクを実行します。ただし、DIにはフレームワークは必要ありません。
  2. 2番目の重要な点は、ここの具体的な工場ファクトリーメソッドの実装ではないということです。ファクトリメソッドのサンプルコードを以下に示します。
  3. 最後に、注意すべき3番目のポイントは、製品間の関係です。この場合、アウトバウンドキューと応答キューです。1つのコンクリートファクトリはAzureキューを生成し、もう1つのファクトリはMSMQを生成します。GoFはこの製品の関係を「ファミリー」と呼び、この場合のファミリーはクラス階層を意味しないことに注意することが重要です。
public class Client {
    private final AbstractFactory_MessageQueue factory;

    public Client(AbstractFactory_MessageQueue factory) {
        // The factory creates message queues either for Azure or MSMQ.
        // The client does not know which technology is used.
        this.factory = factory;
    }

    public void sendMessage() {
        //The client doesn't know whether the OutboundQueue is Azure or MSMQ.
        OutboundQueue out = factory.createProductA();
        out.sendMessage("Hello Abstract Factory!");
    }

    public String receiveMessage() {
        //The client doesn't know whether the ReplyQueue is Azure or MSMQ.
        ReplyQueue in = factory.createProductB();
        return in.receiveMessage();
    }
}

public interface AbstractFactory_MessageQueue {
    OutboundQueue createProductA();
    ReplyQueue createProductB();
}

public class ConcreteFactory_Azure implements AbstractFactory_MessageQueue {
    @Override
    public OutboundQueue createProductA() {
        return new AzureMessageQueue();
    }

    @Override
    public ReplyQueue createProductB() {
        return new AzureResponseMessageQueue();
    }
}

public class ConcreteFactory_Msmq implements AbstractFactory_MessageQueue {
    @Override
    public OutboundQueue createProductA() {
        return new MsmqMessageQueue();
    }

    @Override
    public ReplyQueue createProductB() {
        return new MsmqResponseMessageQueue();
    }
}

ファクトリーメソッド

  1. ここで把握する最も重要な点ConcreteCreator 、クライアントであることです。つまり、クライアントは、親がを定義するサブクラスですfactoryMethod()。これが、ファクトリメソッドが継承によって実装されると言う理由です。
  2. 2番目の重要な点は、ファクトリメソッドパターンはテンプレートメソッドパターンの特殊化にすぎないことを覚えておくことです。2つのパターンは同じ構造を共有します。目的だけが異なります。ファクトリメソッドは創造的(何かを構築する)であるのに対し、テンプレートメソッドは動作的(何かを計算する)です。
  3. 最後に、注意すべき3番目のポイントは、Creator(親)クラスが独自のを呼び出すことfactoryMethod()です。anOperation()親クラスから削除 し、メソッドを1つだけ残しておくと、ファクトリメソッドパターンではなくなります。つまり、ファクトリメソッドは、親クラスのメソッドが2つ未満では実装できません。そして、一方は他方を呼び出す必要があります。
public abstract class Creator {
    public void anOperation() {
        Product p = factoryMethod();
        p.whatever();
    }

    protected abstract Product factoryMethod();
}

public class ConcreteCreator extends Creator {
    @Override
    protected Product factoryMethod() {
        return new ConcreteProduct();
    }
}

その他 &雑貨工場のパターン

GoFは2つの異なるFactoryパターンを定義していますが、これらが存在する唯一のFactoryパターンではないことに注意してください。これらは、必ずしも最も一般的に使用されるFactoryパターンでさえありません。有名な3番目の例は、Effective JavaによるJosh BlochのStatic Factory Patternです。Head First Design Patternsブックには、Simple Factoryと呼ばれるさらに別のパターンが含まれています。

すべてのFactoryパターンがGoFのものと一致しなければならないという仮定の罠に陥らないでください。


3
良い例に基づいた素晴らしく非常に明確な答え、このトピックIMOで最高。
ルークドゥダ

素晴らしい説明。ファクトリメソッドの+1は、その抽象ファクトリメソッドポイントを呼び出す必要があります。この点については、この点を理解していなくても明らかです:自分で呼び出されていないファクトリメソッドがある場合、それを構成する他のクラスによって使用され、そのサブクラスが注入され、抽象ファクトリになります、テンプレートメソッドパターンのようにファクトリ自体が抽象ファクトリメソッドを呼び出さなければならないという点が異なる場合、違いは明確ではなくなります
nits.kk

もう1つ質問です。factoryMethod()常にprotected 「ファクトリーメソッド」パターンのメソッドである必要がありますか?(私はそう思う)
Yaroslav Fedoruk

1
@ YaroslavFedoruk、GoFブックではpublicファクトリメソッドが許可されており、メソッドである必要もありませんabstract。ただし、重要な点は、メソッドは継承を目的としているため、(staticまたは)にすることはできませんfinal。メソッドprotectedabstractここで(必要な)拡張性を強調するために作成しました。
jaco0646

@ nits.kk、あなたは関連する回答に興味があるかもしれません。
jaco0646

26

抽象ファクトリは関連製品を作成するためのインターフェースですが、ファクトリメソッドは1つのメソッドにすぎません。抽象ファクトリは、複数のファクトリメソッドによって実装できます。

抽象ファクトリUML


10
同じ回答をすでにここに投稿しています。この質問が似ていると思われる場合は、代わりに重複として報告してください。
ジャック

11

簡単に理解できるように、この例を検討してください。

電気通信会社は何を提供していますか?たとえば、ブロードバンド、電話回線、モバイルなど、顧客に製品を提供するためのアプリケーションを作成するよう求められます。

一般的に、ここで行うことは、ブロードバンド、電話回線、モバイルなどの製品の作成は、ファクトリーメソッドを使用して、これらの製品のプロパティを把握していることです。

現在、同社は顧客に自社製品のバンドル(ブロードバンド、電話回線、モバイル)をまとめて提供したいと考えており、Abstract Factoryが登場します。

抽象工場は、他の言葉では、自社製品を作成し、責任ある他の工場の構成されている抽象ファクトリーは、自身の責任の点でより意味で、これらの製品を配置する方法を知っています。

この場合、BundleFactoryは抽象ファクトリでBroadbandFactoryありPhonelineFactoryMobileFactoryFactoryです。さらに単純化するために、これらの工場には、個々の製品を初期化するファクトリメソッドがあります。

以下のコードサンプルをご覧ください。

public class BroadbandFactory : IFactory {
    public static Broadband CreateStandardInstance() {
        // broadband product creation logic goes here
    }
}

public class PhonelineFactory : IFactory {
    public static Phoneline CreateStandardInstance() {
        // phoneline product creation logic goes here
    }
}

public class MobileFactory : IFactory {
    public static Mobile CreateStandardInstance() {
        // mobile product creation logic goes here
    }
}

public class BundleFactory : IAbstractFactory {

    public static Bundle CreateBundle() {
        broadband = BroadbandFactory.CreateStandardInstance();
        phoneline = PhonelineFactory.CreateStandardInstance();
        mobile = MobileFactory.CreateStandardInstance();

        applySomeDiscountOrWhatever(broadband, phoneline, mobile);
    }

    private static void applySomeDiscountOrWhatever(Broadband bb, Phoneline pl, Mobile m) {
        // some logic here
        // maybe manange some variables and invoke some other methods/services/etc.
    }
}

お役に立てれば。


1
staticどちらのGoFファクトリパターンにもメソッドはありません。これは間違っています。
jaco0646

5

実生活の例。(覚えやすい)

工場

あなたが家を建てて、ドアのために大工に近づくと想像してください。あなたはドアとあなたの要件のための測定を与えると、彼はあなたのためにドアを構築します。この場合、大工はドアの工場です。仕様は工場への入力であり、ドアは工場からの出力または製品です。

抽象ファクトリー

ここで、ドアの同じ例を考えます。あなたは大工に行くことができますか、またはプラスチック製のドアの店やPVCの店に行くことができます。それらはすべてドア工場です。状況に基づいて、どのような工場にアプローチする必要があるかを決定します。これは抽象ファクトリーのようなものです。

ここでは、ファクトリメソッドパターンと抽象ファクトリパターンの両方について、問題を説明せずに、上記のパターンを使用して問題を解決することから説明しました https://github.com/vikramnagineni/Design-Patterns/tree/master


3

クラスAはインターフェイスBでプログラムされているため、ほとんどの場合、プロダクションコードでは抽象ファクトリパターンを使用します。AはBのインスタンスを作成する必要があります。したがって、AはBのインスタンスを生成するファクトリオブジェクトを持つ必要があります。 。したがって、AはBの具体的なインスタンスに依存していません。


3

動機の違いを理解する:

オブジェクトとオブジェクトの相互関係の具体的な実装があるツールを構築しているとします。オブジェクトのバリエーションを予測しているので、オブジェクトのバリアントを作成する責任を別のオブジェクトに割り当てて、間接指定を作成しました(これを抽象ファクトリと呼びます)。これらのオブジェクトのバリアントを必要とする将来の拡張を予測するため、この抽象化は強力な利点を見つけます。

この考え方のもう1つの興味深い動機は、グループ全体からのオブジェクトのすべてまたは1つのオブジェクトに対応するバリアントがある場合です。いくつかの条件に基づいて、いずれかのバリアントが使用され、いずれの場合もすべてのオブジェクトは同じバリアントでなければなりません。これは、オブジェクトのバリアントが共通のユニフォームコントラクト(広義にはインターフェイス)に従っている限り、具体的な実装コードが壊れることはないと考えがちなので、少し直観に反するかもしれません。ここで興味深い事実は、プログラミングコントラクトで期待される動作をモデル化できない場合は特に、常にそうであるとは限らないことです。

シンプルな(GoFからアイデアを借りた)のは、GUIアプリケーションが、MS、Mac、またはFedora OSのルックアンドフィールをエミュレートする仮想モニターと言うものです。ここで、たとえば、ウィンドウ、ボタンなどのすべてのウィジェットオブジェクトに、MSバリアントがあり、MACバリアントから派生したスクロールバーを除くと、ツールの目的が失敗します。

これらの上記のケースは、抽象ファクトリパターンの基本的な必要性を形成します。

一方、フレームワークを使用して、多くの人がそのフレームワークを使用してさまざまなツール(上記の例のようなもの)を構築できるように想像してください。フレームワークのアイデアそのものにより、ロジックで具象オブジェクトを使用できなかったとしても、その必要はありません。むしろ、さまざまなオブジェクトとそれらがどのように相互作用するかの間のいくつかの高レベルのコントラクトを配置します。あなた(フレームワーク開発者として)は非常に抽象的なレベルにとどまりますが、ツールの各ビルダーはフレームワークコンストラクトに従う必要があります。ただし、それら(ツールビルダー)は、作成するオブジェクトと、作成するすべてのオブジェクトがどのように相互作用するかを自由に決定できます。前のケース(抽象ファクトリパターン)とは異なり、あなた(フレームワーク作成者として)この場合、具象オブジェクトを処理する必要はありません。むしろ、オブジェクトの契約レベルに留まることができます。さらに、前の動機の2番目の部分とは異なり、ユーザーまたはツールビルダーは、バリアントのオブジェクトを混合する状況に直面することはありません。ここでは、フレームワークコードは契約レベルのままですが、すべてのツールビルダーは(ケース自体の性質により)独自のオブジェクトの使用に制限さています。この場合のオブジェクトの作成は、各実装者に委任され、フレームワークプロバイダーは、オブジェクトを作成して返すための統一されたメソッドを提供します。このようなメソッドは、フレームワーク開発者がコードを続行するのに不可欠であり、ファクトリメソッド基になるパターンのファクトリメソッドパターン)と呼ばれる特別な名前を持っています。

いくつかのメモ:

  • 「テンプレートメソッド」に精通している場合は、任意の形式のフレームワークに関連するプログラムの場合に、ファクトリメソッドがテンプレートメソッドから呼び出されることがよくあります。対照的に、アプリケーションプログラムのテンプレートメソッドは、多くの場合、特定のアルゴリズムの単純な実装であり、ファクトリーメソッドはありません。
  • さらに、考えを完全にするために、フレームワーク(上記)を使用して、ツールビルダーが具象オブジェクトを作成する代わりに、各ファクトリーメソッド内でツールを構築する場合、アブストラクトに責任をさらに委任する場合があります。 -factoryオブジェクトは、将来の拡張のために具象オブジェクトのバリエーションを予測するツールビルダーを提供します。

サンプルコード:

//Part of framework-code
BoardGame {
    Board createBoard() //factory method. Default implementation can be provided as well
    Piece createPiece() //factory method

    startGame(){        //template method
         Board borad = createBoard()
         Piece piece = createPiece()
         initState(board, piece)
    }
}


//Part of Tool-builder code
Ludo inherits  BoardGame {
     Board createBoard(){ //overriding of factory method
         //Option A: return new LudoBoard() //Lodu knows object creation
         //Option B: return LudoFactory.createBoard() //Lodu asks AbstractFacory
     }
….
}

//Part of Tool-builder code
Chess inherits  BoardGame {
    Board createBoard(){ //overriding of factory method
        //return a Chess board
    }
    ….
}

3
  1. 私の最初の質問は、抽象ファクトリーについてです。その役割は、単一のコンクリートオブジェクトだけでなく、使用する具体的なファクトリに依存するコンクリートオブジェクトのファミリを作成できるようにすることですか?

はい。Abstract Factoryの目的は次のとおりです。

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


  1. 抽象ファクトリーは、呼び出すメソッドに応じて、非常に大きなオブジェクトを1つだけ返すのか、それとも多くのオブジェクトを返すのですか?

理想的には、クライアントが呼び出しているメソッドごとに1つのオブジェクトを返す必要があります。

  1. 私の理解では、ファクトリー・メソッド・パターンにはCreatorインターフェースがあり、これにより、具象化するConcreteProductを、ConcreteCreatorが管理できるようになります。これは、継承を使用してオブジェクトのインスタンス化を処理することの意味ですか?

はい。ファクトリメソッドは継承を使用します。

  1. 抽象ファクトリパターンは、オブジェクトのインスタンス化の責任を合成を介して別のオブジェクトに委任しますか?これは何を意味するのでしょうか?

AbstractFactoryはFactoryMethodを定義し、ConcreteFactoryはConcreteProductの構築を担当します。この 記事のコード例に従ってください

詳細については、関連するSEの投稿をご覧ください。

ファクトリパターンと抽象ファクトリパターンの基本的な違いは何ですか?

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


3

ファクトリメソッドは継承に依存します。オブジェクトの作成は、オブジェクトを作成するファクトリメソッドを実装するサブクラスに委任されます。

抽象ファクトリはオブジェクト構成に依存しています。オブジェクトの作成は、ファクトリインターフェースで公開されているメソッドに実装されています。

Factoryの概要図とAbstract Factoryパターン

図

Factoryメソッドの詳細については、この記事を参照してください

抽象ファクトリメソッドの詳細については、この記事を参照してください


2

最小限のインターフェイスで非常に簡単にするため、「// 1」にフォーカスしてください:

class FactoryProgram
    {
        static void Main()
        {
            object myType = Program.MyFactory("byte");
            Console.WriteLine(myType.GetType().Name);

            myType = Program.MyFactory("float"); //3
            Console.WriteLine(myType.GetType().Name);

            Console.ReadKey();
        }

        static object MyFactory(string typeName)
        {
            object desiredType = null; //1
            switch (typeName)
            {
                case "byte": desiredType = new System.Byte(); break; //2
                case "long": desiredType = new System.Int64(); break;
                case "float": desiredType = new System.Single(); break;
                default: throw new System.NotImplementedException();
            }
            return desiredType;
        }
    }

ここで重要なポイント:1. FactoryおよびAbstractFactoryメカニズムは継承を使用する必要があります(System.Object-> byte、float ...)。したがって、プログラムに継承がある場合、ファクトリー(Abstract Factoryはおそらく存在しない可能性が最も高い)は、設計2によってすでにそこにあります。抽象ファクトリでは、戻り値の型はインターフェイスになります。

interface IVehicle { string VehicleName { get; set; } }
interface IVehicleFactory
    {
        IVehicle CreateSingleVehicle(string vehicleType);
    }
class HondaFactory : IVehicleFactory
    {
        public IVehicle CreateSingleVehicle(string vehicleType)
        {
            switch (vehicleType)
            {
                case "Sports": return new SportsBike();
                case "Regular":return new RegularBike();
                default: throw new ApplicationException(string.Format("Vehicle '{0}' cannot be created", vehicleType));
            }
        }
    }
class HeroFactory : IVehicleFactory
    {
        public IVehicle CreateSingleVehicle(string vehicleType)
        {
            switch (vehicleType)
            {
                case "Sports":  return new SportsBike();
                case "Scooty": return new Scooty();
                case "DarkHorse":return new DarkHorseBike();
                default: throw new ApplicationException(string.Format("Vehicle '{0}' cannot be created", vehicleType));
            }
        }
    }

class RegularBike : IVehicle { public string VehicleName { get { return "Regular Bike- Name"; } set { VehicleName = value; } } }
class SportsBike : IVehicle { public string VehicleName { get { return "Sports Bike- Name"; } set { VehicleName = value; } } }
class RegularScooter : IVehicle { public string VehicleName { get { return "Regular Scooter- Name"; } set { VehicleName = value; } } }
class Scooty : IVehicle { public string VehicleName { get { return "Scooty- Name"; } set { VehicleName = value; } } }
class DarkHorseBike : IVehicle { public string VehicleName { get { return "DarkHorse Bike- Name"; } set { VehicleName = value; } } }

class Program
{
    static void Main(string[] args)
    {
        IVehicleFactory honda = new HondaFactory(); //1
        RegularBike hondaRegularBike = (RegularBike)honda.CreateSingleVehicle("Regular"); //2
        SportsBike hondaSportsBike = (SportsBike)honda.CreateSingleVehicle("Sports");
        Console.WriteLine("******* Honda **********"+hondaRegularBike.VehicleName+ hondaSportsBike.VehicleName);

        IVehicleFactory hero = new HeroFactory();
        DarkHorseBike heroDarkHorseBike = (DarkHorseBike)hero.CreateSingleVehicle("DarkHorse");
        SportsBike heroSportsBike = (SportsBike)hero.CreateSingleVehicle("Sports");
        Scooty heroScooty = (Scooty)hero.CreateSingleVehicle("Scooty");
        Console.WriteLine("******* Hero **********"+heroDarkHorseBike.VehicleName + heroScooty.VehicleName+ heroSportsBike.VehicleName);

        Console.ReadKey();
    }
}

重要なポイント:1.要件:ホンダは「Regular」、「Sports」を作成しますが、ヒーローは「DarkHorse」、「Sports」、および「Scooty」を作成します。2.なぜ2つのインターフェースなのか 1つは製造元タイプ(IVehicleFactory)用で、もう1つは製品ファクトリー(IVehicle)用です。2つのインターフェースを理解する他の方法は、抽象ファクトリが関連オブジェクト2を作成することです。キャッチは、IVehicleFactoryの子が返され、IVehicleが(ファクトリ内のコンクリートの代わりに)です。だから私は親変数(IVehicle);を取得します。次に、CreateSingleVehicleを呼び出して実際の具象型を作成し、親オブジェクトを実際の子オブジェクトにキャストします。私がした場合どうなるでしょうRegularBike heroRegularBike = (RegularBike)hero.CreateSingleVehicle("Regular");。ApplicationExceptionが発生します。そのため、必要に応じて説明する汎用の抽象ファクトリが必要です。



0

私はいつでもファクトリーメソッドよりも抽象ファクトリーを優先します。上記のTom Dallingの例(素晴らしい説明)から、必要なのはコンストラクターに異なるファクトリーを渡すこと(ここで使用しているコンストラクター依存関係の注入)であるという点で、Abstract Factoryの方がより構成可能であることがわかります。ただし、ファクトリメソッドでは、新しいクラス(より多くの管理対象)を導入し、サブクラス化を使用する必要があります。常に継承よりも構成を優先します。


0

正確に説明させてください。ほとんどの回答はすでに説明されており、図と例も提供されています。だから私の答えはただ一つのライナーになるでしょう。私自身の言葉:- 「抽象ファクトリパターンは、複数のファクトリメソッド実装の上に抽象層を追加します。抽象ファクトリは、 1つまたは複数のファクトリメソッドパターンを含むか、または合成することを意味します。」


これは正しくありません。これは、Abstract Factoryが工場の工場にすぎないという、あまりにも一般的な誤解です。
jaco0646

0

上記の回答の多くは、抽象ファクトリパターンとファクトリメソッドパターン間のコード比較を提供していません。以下は、Javaを介して説明する私の試みです。簡単な説明が必要な人に役立つことを願っています。

GoFが適切に述べているように、Abstract Factoryは、具象クラスを指定せずに、関連オブジェクトまたは依存オブジェクトのファミリーを作成するためのインターフェースを提供します。

        public class Client {
            public static void main(String[] args) {
               ZooFactory zooFactory = new HerbivoreZooFactory();       
               Animal animal1 = zooFactory.animal1();
               Animal animal2 = zooFactory.animal2();
               animal1.sound();
               animal2.sound();

               System.out.println();

               AnimalFactory animalFactory = new CowAnimalFactory();
               Animal animal = animalFactory.createAnimal();
               animal.sound();
            }
        }

        public interface Animal {
            public void sound();
        }

        public class Cow implements Animal {

            @Override
            public void sound() {
                System.out.println("Cow moos");
            }

        }

        public class Deer implements Animal {

            @Override
            public void sound() {
                System.out.println("Deer grunts");
            }

        }

        public class Hyena implements Animal {

            @Override
            public void sound() {
                System.out.println("Hyena.java");
            }

        }

        public class Lion implements Animal {

            @Override
            public void sound() {
                System.out.println("Lion roars");
            }

        }

        public interface ZooFactory {
            Animal animal1();

            Animal animal2();
        }

        public class CarnivoreZooFactory implements ZooFactory {

            @Override
            public Animal animal1() {
                return new Lion();
            }

            @Override
            public Animal animal2() {
                return new Hyena();
            }

        }

        public class HerbivoreZooFactory implements ZooFactory{

            @Override
            public Animal animal1() {
                return new Cow();
            }

            @Override
            public Animal animal2() {
                return new Deer();
            }

        }

        public interface AnimalFactory {
            public Animal createAnimal();
        }

        public class CowAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Cow();
            }

        }

        public class DeerAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Deer();
            }

        }

        public class HyenaAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Hyena();
            }

        }

        public class LionAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Lion();
            }

        }

これは正しくありません。このコードは、抽象ファクトリーがファクトリーのファクトリーに過ぎないという、あまりにも一般的な誤解を実装しています。
jaco0646

1
@ jaco0646ファクトリメソッドパターンでは、FactoryImplから具体的な製品を1つだけ取得することに焦点が置かれていると思います。一方、抽象的なファクトリパターンでは、FactoryImplは複数の類似/関連するConcreteProductsを提供する責任があり、FactoryInterfaceはそのためにコントラクトを提供します。つまり、ZooFactoryはファクトリーのファクトリーではなく、相互に関連する具象製品をImplsが提供するインターフェースにすぎません。同意しない場合は、自由に私の理解を訂正してください。
Jatin Shashoo 2018年

ファクトリーメソッドはテンプレートメソッドパターンの特殊化であるため、ファクトリーメソッドでは、サブクラス化による継承に重点が置かれます。上記のトップ投票の回答は、まともなコード例を示しています。
jaco0646 2018年

@ jaco0646 1.これは、上記の例では、AnimalFactoryのインターフェースを使用してその実装を提供する代わりに、クラスを使用して、サブクラスであるCowAnimalFactory、LionAnimalFactoryなどのメソッドcreateAnimal()をオーバーライドする必要があったことを意味しますか?2.また、ZooFactoryの例についてはどう思いますか?
Jatin Shashoo 2018年

最初の質問へ:はい。もう1つは、個々の回答を批判し続けるのではなく、このスレッドに自分の回答を追加しました。
jaco0646 2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.