やあ!今日は引き続きデザイン パターンの学習を進め、ファクトリー メソッド パターンについて説明します。
それが何なのか、そしてこのパターンがどのようなタスクに適しているのかがわかります。このデザインパターンを実際に考察し、その構造を検討していきます。すべてを明確にするには、次のトピックを理解する必要があります。
どのような結論が出せるでしょうか?
上の図は、ファクトリ メソッド パターンの一般的な構造を示しています。ここで他に重要なことは何ですか?

- Java の継承。
- Java の抽象メソッドとクラス
ファクトリメソッドはどのような問題を解決しますか?
すべての工場設計パターンには、作成者 (工場自体) と製品 (工場によって作成されるオブジェクト) という 2 種類の参加者がいます。次の状況を想像してください。CodeGym ブランドの車を生産する工場があります。さまざまなタイプのボディを持つ車のモデルを作成する方法を知っています。- セダン
- ステーションワゴン
- クーペ
- コードジムセダン
- コードジムのステーションワゴン
- コードジム クーペ
- ワンオートセダン
- OneAutoステーションワゴン
- ワンオート クーペ
ファクトリーパターンについて少し
以前に小さな仮想コーヒー ショップを構築したことを思い出してください。簡単な工場の助けを借りて、私たちはさまざまな種類のコーヒーの作り方を学びました。今日はこの例を作り直します。シンプルな工場を備えたコーヒーショップの様子を思い出してみましょう。コーヒー教室がありました:
public class Coffee {
public void grindCoffee(){
// Grind the coffee
}
public void makeCoffee(){
// Brew the coffee
}
public void pourIntoCup(){
// Pour into a cup
}
}
そして、私たちの工場で生産できる特定の種類のコーヒーに対応するいくつかの子クラスがあります。
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
注文を簡単にするために列挙型を作成しました。
public enum CoffeeType {
ESPRESSO,
AMERICANO,
CAFFE_LATTE,
CAPPUCCINO
}
コーヒー工場自体はこんな感じでした。
public class SimpleCoffeeFactory {
public Coffee createCoffee(CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new Americano();
break;
case ESPRESSO:
coffee = new Espresso();
break;
case CAPPUCCINO:
coffee = new Cappuccino();
break;
case CAFFE_LATTE:
coffee = new CaffeLatte();
break;
}
return coffee;
}
}
そして最終的に、コーヒーショップ自体は次のようになりました。
public class CoffeeShop {
private final SimpleCoffeeFactory coffeeFactory;
public CoffeeShop(SimpleCoffeeFactory coffeeFactory) {
this.coffeeFactory = coffeeFactory;
}
public Coffee orderCoffee(CoffeeType type) {
Coffee coffee = coffeeFactory.createCoffee(type);
coffee.grindCoffee();
coffee.makeCoffee();
coffee.pourIntoCup();
System.out.println("Here's your coffee! Thanks! Come again!");
return coffee;
}
}
シンプルな工場を近代化する
私たちのコーヒーショップはとても順調に経営しています。非常に多いので、拡張を検討しています。新しい場所をいくつかオープンしたいと考えています。私たちは大胆で進取的なので、退屈なコーヒーショップを作り変えるつもりはありません。それぞれのお店に特別な工夫をしてもらいたいと思っています。したがって、まずはイタリア店とアメリカ店の 2 店舗をオープンします。これらの変更はインテリアデザインだけでなく、提供されるドリンクにも影響を与えます。- イタリアのコーヒーショップでは、イタリアのブランドコーヒーのみを使用し、特別な挽き方と焙煎を行います。
- アメリカの店舗ではより多くの量があり、注文ごとにマシュマロを提供します。
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
しかし、今では 8 つになります:
public class ItalianStyleAmericano extends Coffee {}
public class ItalianStyleCappucino extends Coffee {}
public class ItalianStyleCaffeLatte extends Coffee {}
public class ItalianStyleEspresso extends Coffee {}
public class AmericanStyleAmericano extends Coffee {}
public class AmericanStyleCappucino extends Coffee {}
public class AmericanStyleCaffeLatte extends Coffee {}
public class AmericanStyleEspresso extends Coffee {}
現在のビジネスモデルを維持したいので、orderCoffee(CoffeeType type)
手法の変更はできるだけ少なくしたいと考えています。見てみましょう:
public Coffee orderCoffee(CoffeeType type) {
Coffee coffee = coffeeFactory.createCoffee(type);
coffee.grindCoffee();
coffee.makeCoffee();
coffee.pourIntoCup();
System.out.println("Here's your coffee! Thanks! Come again!");
return coffee;
}
どのような選択肢があるでしょうか? そうですね、ファクトリーの書き方はすでに知っていますよね? すぐに思い浮かぶ最も簡単な方法は、2 つの同様のファクトリーを作成し、目的の実装をコーヒーショップのコンストラクターに渡すことです。これでは喫茶店の格は変わりません。まず、新しいファクトリ クラスを作成し、単純なファクトリを継承させて、createCoffee(CoffeeType type)
メソッドをオーバーライドする必要があります。イタリア式コーヒーとアメリカン式コーヒーを作成する工場を書いてみましょう。
public class SimpleItalianCoffeeFactory extends SimpleCoffeeFactory {
@Override
public Coffee createCoffee(CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new ItalianStyleAmericano();
break;
case ESPRESSO:
coffee = new ItalianStyleEspresso();
break;
case CAPPUCCINO:
coffee = new ItalianStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new ItalianStyleCaffeLatte();
break;
}
return coffee;
}
}
public class SimpleAmericanCoffeeFactory extends SimpleCoffeeFactory{
@Override
public Coffee createCoffee (CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new AmericanStyleAmericano();
break;
case ESPRESSO:
coffee = new AmericanStyleEspresso();
break;
case CAPPUCCINO:
coffee = new AmericanStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new AmericanStyleCaffeLatte();
break;
}
return coffee;
}
}
これで、必要なファクトリ実装を CoffeeShop に渡すことができます。さまざまなコーヒー ショップにコーヒーを注文するコードがどのようになるかを見てみましょう。たとえば、イタリア風カプチーノとアメリカ風カプチーノ:
public class Main {
public static void main(String[] args) {
/*
Order an Italian-style cappuccino:
1. Create a factory for making Italian coffee
2. Create a new coffee shop, passing the Italian coffee factory to it through the constructor
3. Order our coffee
*/
SimpleItalianCoffeeFactory italianCoffeeFactory = new SimpleItalianCoffeeFactory();
CoffeeShop italianCoffeeShop = new CoffeeShop(italianCoffeeFactory);
italianCoffeeShop.orderCoffee(CoffeeType.CAPPUCCINO);
/*
Order an American-style cappuccino
1. Create a factory for making American coffee
2. Create a new coffee shop, passing the American coffee factory to it through the constructor
3. Order our coffee
*/
SimpleAmericanCoffeeFactory americanCoffeeFactory = new SimpleAmericanCoffeeFactory();
CoffeeShop americanCoffeeShop = new CoffeeShop(americanCoffeeFactory);
americanCoffeeShop.orderCoffee(CoffeeType.CAPPUCCINO);
}
}
希望する工場をそれぞれに渡して、2 つの異なるコーヒー ショップを作成しました。一方で、私たちは目的を達成しましたが、その一方で... どういうわけか、これは起業家にとってうまくいきません... 何が問題なのか考えてみましょう。まず工場の多さ。何?さて、新しい場所ごとに独自の工場を作成し、それに加えて、コーヒーショップを作成するときに関連する工場がコンストラクターに確実に渡されるようにする必要がありますか? 第二に、それはまだ単純な工場です。少しだけ近代化されました。しかし、私たちは新しいパターンを学ぶためにここにいます。第三に、別のアプローチは可能ではないでしょうか? コーヒーの準備に関するすべての問題をCoffeeShop
さまざまなスタイルのコーヒーを作るための十分な柔軟性を同時に維持しながら、コーヒーの作成と注文へのサービスのプロセスをリンクすることにより、クラスを実現します。答えは「はい、できます」です。これをファクトリメソッドデザインパターンと呼びます。
シンプルファクトリーからファクトリーメソッドへ
タスクをできるだけ効率的に解決するには:createCoffee(CoffeeType type)
メソッドをクラスに返しますCoffeeShop
。- このメソッドを抽象化します。
- クラス
CoffeeShop
自体が抽象化されます。 - クラス
CoffeeShop
には子クラスがあります。
CoffeeShop
実行するクラスの子孫にすぎません。createCoffee(CoffeeType type)
さあ、一歩ずつ。ステップ 1.Coffee
クラスを抽象化します。当社には、異なる製品の 2 つのファミリーがあります。それでも、イタリアとアメリカのコーヒーには共通の祖先、つまりCoffee
クラスがあります。抽象化するのが適切でしょう:
public abstract class Coffee {
public void makeCoffee(){
// Brew the coffee
}
public void pourIntoCup(){
// Pour into a cup
}
}
ステップ 2.CoffeeShop
抽象createCoffee(CoffeeType type)
メソッド を使用して抽象を作成する
public abstract class CoffeeShop {
public Coffee orderCoffee(CoffeeType type) {
Coffee coffee = createCoffee(type);
coffee.makeCoffee();
coffee.pourIntoCup();
System.out.println("Here's your coffee! Thanks! Come again!");
return coffee;
}
protected abstract Coffee createCoffee(CoffeeType type);
}
ステップ 3. 抽象コーヒー ショップの子孫であるイタリアン コーヒー ショップを作成します。createCoffee(CoffeeType type)
イタリアのレシピの詳細を考慮して、そのメソッド を実装します。
public class ItalianCoffeeShop extends CoffeeShop {
@Override
public Coffee createCoffee (CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new ItalianStyleAmericano();
break;
case ESPRESSO:
coffee = new ItalianStyleEspresso();
break;
case CAPPUCCINO:
coffee = new ItalianStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new ItalianStyleCaffeLatte();
break;
}
return coffee;
}
}
ステップ 4. アメリカンスタイルのコーヒーショップでも同じことを行います
public class AmericanCoffeeShop extends CoffeeShop {
@Override
public Coffee createCoffee(CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new AmericanStyleAmericano();
break;
case ESPRESSO:
coffee = new AmericanStyleEspresso();
break;
case CAPPUCCINO:
coffee = new AmericanStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new AmericanStyleCaffeLatte();
break;
}
return coffee;
}
}
ステップ 5. アメリカとイタリアのラテがどのように見えるかを確認してください:
public class Main {
public static void main(String[] args) {
CoffeeShop italianCoffeeShop = new ItalianCoffeeShop();
italianCoffeeShop.orderCoffee(CoffeeType.CAFFE_LATTE);
CoffeeShop americanCoffeeShop = new AmericanCoffeeShop();
americanCoffeeShop.orderCoffee(CoffeeType.CAFFE_LATTE);
}
}
おめでとう。例としてコーヒーショップを使用してファクトリーメソッド設計パターンを実装しました。
ファクトリーメソッドの背後にある原理
ここで、何が得られたのかをさらに詳しく考えてみましょう。以下の図は、結果として得られるクラスを示しています。緑色のブロックはクリエーター クラス、青色のブロックはプロダクト クラスです。
- すべての製品は抽象
Coffee
クラスの実装です。 - すべての作成者は抽象
CoffeeShop
クラスの実装です。 - 2 つの並列クラス階層が表示されます。
- 製品の階層。イタリア人の子孫とアメリカ人の子孫がいます
- クリエイターの階層。イタリア人の子孫とアメリカ人の子孫がいます
- スーパー
CoffeeShop
クラスには、どの特定の製品 (Coffee
) が作成されるかについての情報はありません。 - スーパー
CoffeeShop
クラスは、特定の製品の作成をその子孫に委任します。 - クラスの各子孫は、それぞれの固有の機能に従ってファクトリ メソッド
CoffeeShop
を実装します。createCoffee()
言い換えれば、プロデューサ クラスの実装は、プロデューサ クラスの詳細に基づいて特定の製品を準備します。
ファクトリメソッドの構造

- Creator クラスは、ファクトリ メソッドを除く、製品と対話するすべてのメソッドを実装します。
- 抽象
factoryMethod()
メソッドは、クラスのすべての子孫によって実装される必要がありますCreator
。 - このクラスは、プロダクトを直接作成するメソッド
ConcreteCreator
を実装します。factoryMethod()
- このクラスは、特定の製品の作成を担当します。これは、これらの製品の作成に関する情報が含まれる唯一のクラスです。
- すべての製品は共通のインターフェイスを実装する必要があります。つまり、製品は共通の製品クラスの子孫である必要があります。これは、プロダクトを使用するクラスが、特定の実装ではなく抽象化としてプロダクトを操作できるようにするために必要です。
GO TO FULL VERSION