web-dev-qa-db-ja.com

「ファクトリーメソッドはテンプレートメソッドの特殊化」です。どうやって?

2つの間の類似点と相違点:

テンプレートメソッド

  • 継承に依存します。
  • アルゴリズムのステップを定義し、それらを実装するタスクをサブクラスに任せます。

ファクトリーメソッド

  • 継承に依存します。
  • スーパークラスは、オブジェクトを作成するためのインターフェースを定義します。サブクラスは、インスタンス化する具象クラスを決定します。

2つ並べて:

enter image description here

「ファクトリーメソッドはテンプレートメソッドの特殊化」というフレーズの意味がわかりません(これは Head First Design Patternsの本 にあります)。 Beverageには、prepareというメソッドfinalがあり、一連のステップを定義しています。 PizzaStoreにはabstractのメソッドがあり、サブクラスがそれを再定義します。後者はどのように前者の専門分野ですか?

10

Beverageには、サブクラスで実装されているprepareboilWaterなどの抽象メソッドを呼び出す(「テンプレート」)メソッドbrewがあります。テンプレートメソッドを基本クラスに配置することは、基本的にパターンではなく、抽象メソッドがパブリックであると想定して、他の場所に配置することもできます。しかし、本質的には、オーバーライドする必要があり、「アルゴリズムテンプレート」のギャップを埋める抽象メソッドがあるということです。

ファクトリーメソッドは、抽象メソッドが上書きされるクラスにも関係します。コアポイントは、そのメソッドの呼び出し元が、作成されたオブジェクトの正確なタイプを知る必要がないことです。 PizzaStoreでは、抽象メソッドcreatePizzaをどこかから呼び出さなければならないことに注意してください-メソッドcreateLotsOfPizzaとしましょう。

これにより、後者がテンプレート方式になり、「ピザを作成するアルゴリズム」の特定のステップは、埋められるギャップになります。現在、「ファクトリメソッドパターン」は「テンプレートメソッド」パターンの特殊なケースであると言って、それはおそらく言葉の不正確な使い方です。特に「ファクトリメソッド」は「テンプレートメソッド」ではありませんが、fromからテンプレートメソッドである可能性があります。より正確に言うと、

"ファクトリメソッドパターンは通常、テンプレートメソッドパターンの特殊なケースと組み合わせて使用​​されます"

その本の著者が表現したかったのはそれだと思います。

6
Doc Brown

"ファクトリメソッドはテンプレートメソッドの特殊化です"は誤った特徴付けだと思います。テンプレートメソッドパターンは、ファクトリメソッドパターンの単なるvariationであると言う方がより正確だと思います。

さらに、テンプレートメソッドパターンは、継承とメソッドのオーバーライドによって自然に発生するため、実際には(Gang of Fourの意味で)まったくパターンではないと主張します。上の図のテンプレートパターンの図では、子孫クラスが独自の動作で基本クラスのメソッドをオーバーライドしているだけであることがわかります。

全体的に見て、ソフトウェアパターン(ギャングオブフォーバラエティの)は、プログラミング言語の欠陥に対する実際の回避策であり、テンプレートパターンは、オブジェクト指向言語がすでにネイティブで利用できる機能を再表現するだけです。

2
Robert Harvey

この特徴付けでは、ヘッドファーストは単に間違っていると思います。

ウィキペディアでは、テンプレートメソッドを次のように定義しています。

ソフトウェアエンジニアリングでは、テンプレートメソッドパターンは動作のアルゴリズムのプログラムスケルトンを定義する動作設計パターンであり、サブクラスにいくつかのステップを延期します。

(それはGoFを参照しています。)

また、ファクトリーメソッドは次のように定義されます。

クラス・ベースのプログラミングでは、ファクトリー・メソッド・パターンは、作成されるオブジェクトの正確なクラスを指定する必要なしに、ファクトリー・メソッドを使用してオブジェクトの作成の問題に対処する作成パターンです。

C++では継承が両方の重要な部分であることを除いて、2つの間に重複はありません。ただし、実装の継承(Javaではextends)とインターフェースの実装(Javaではimplements)を区別する言語では、ファクトリのインターフェース実装で十分なので、この共通性さえ存在しません。メソッドですが、テンプレートメソッドではありません。また、C++では、前者には純粋な実装継承(インターフェース継承なし、つまりプライベート継承またはCRTPなし)を使用できますが、後者には使用できません。

それとは別に? 1つは行動パターン、もう1つは創造パターンです。 1つは操作の概要を説明するもので、一部の重要な部分は特殊なサブクラスで埋める必要があります。もう1つは非常に単純なコントラクトを指定し、実装全体を具体的なインスタンスに任せます。それらは完全に異なります。

私の意見では、引用された行は単に間違っています。これは本の明白なエラーであるか、または(可能性は低い)コンテキスト外であり、異なる解釈が必要です。

1
Sebastian Redl