blog

最初のデザインパターン:ファクトリー・メソッド・パターン

ファクトリーメソッドパターンはオブジェクトを作成するインターフェースを定義しますが、どのクラスをインスタンス化するかはサブクラスに任せます。ファクトリーメソッドによって、クラスはインスタンス化をサブク...

Jul 2, 2020 · 6 min. read
シェア

テキスト

I. 定義

ファクトリー・メソッド・パターンは、オブジェクトを生成するインターフェースを定義しますが、どのクラスをインスタンス化するかはサブクラスに任せます。ファクトリーメソッドによって、クラスはインスタンス化をサブクラスに委ねることができます。

要点は

  • 具体的なオブジェクトはサブクラス化によって作成されます。クライアントは、使用する抽象型だけを知っていればよいのです。
  • サブクラスがインスタンス化するクラスを決めるということは、クリエーター・クラスを書くときに、実際にどの商品が作られるかを知る必要がないということです。どのクリエイター・サブクラスを使用するかという選択は、どの製品が実際に作成されるかを自然に決定します。
  • オブジェクトは、定義されたファクトリーメソッドによって一律に作成されます。

II.実現へのステップ

、製品抽象クラスを作成

/**
 * 商品抽象クラス
 */
public abstract class Product {
 
 String name;
 
 public String getName() {
 return name;
 }
}

、具体的な製品を作成し、製品の抽象クラスを継承します。

製品 A1

/**
 * 製品A1
 */
public class ConcreteProductA1 extends Product {
 
 public ConcreteProductA1() {
 name = "ConcreteProductA1";
 }
}

製品 A2

/**
 * 製品A2
 */
public class ConcreteProductA2 extends Product {
 
 public ConcreteProductA2() {
 name = "ConcreteProductA2";
 }
}

製品 B1

/**
 * 製品 B1
 */
public class ConcreteProductB1 extends Product {
 
 public ConcreteProductB1() {
 name = "ConcreteProductB1";
 }
}

製品 B2

/**
 * 製品B2
 */
public class ConcreteProductB2 extends Product {
 
 public ConcreteProductB2() {
 name = "ConcreteProductB2";
 }
}

抽象クラスを作成し、製品を作成するためのファクトリーメソッドを定義します。

作成者は通常、製品を使用する必要があるクラスであり、必要な製品はクラス内のファクトリーメソッドを通じて作成されます。

/**
 * 抽象クラスを作成する
 */
public abstract class Creator {
 /**
 * 商品を作成する
 */
 protected abstract Product createProduct(String productType);
}

具象クリエーターを作成し、クリエーター抽象クラスを継承します。

特定の作成者は、製品を作成するファクトリーメソッドを実装する必要があります。

クリエーター 2

/**
 * 作成者 1
 */
public class ConcreteCreator1 extends Creator {
 @Override
 protected Product createProduct(String productType) {
 // 具体的な作成者が、どのクラスのオブジェクトを作成するかを決める
 if ("A".equals(productType)) {
 return new ConcreteProductA1();
 } else if ("B".equals(productType)) {
 return new ConcreteProductB1();
 }
 return null;
 }
}

クリエーター 2

/**
 * クリエーター 2
 */
public class ConcreteCreator2 extends Creator {
 @Override
 protected Product createProduct(String productType) {
 // 具体的な作成者が、どのクラスのオブジェクトを作成するかを決める
 if ("A".equals(productType)) {
 return new ConcreteProductA2();
 } else if ("B".equals(productType)) {
 return new ConcreteProductB2();
 }
 return null;
 }
}

作成者はファクトリーメソッドで製品を作成します。

public class Test {
 
 public static void main(String[] args) {
 // 作成者 1
 Creator creator1 = new ConcreteCreator1();
 // クリエーター 2
 Creator creator2 = new ConcreteCreator2();
 
 // ファクトリーメソッドで商品を作る
 Product product = creator1.createProduct("A");
 System.out.println("Creator 1が商品Aを作成する:" + product.getName());
 product = creator2.createProduct("A");
 System.out.println("クリエイター2が商品Aを作成する" + product.getName());
 }
}

3番目は栗

背景

チーズピザ、クラムピザ、ベジピザなど、たくさんの種類のピザを売るピザ屋があるとします。事業は成功しているので、あなたはフランチャイズを促進することを計画しています。

フランチャイズ経営の品質を確保するためには、フランチャイズが一定の製造工程を使えるようにしたいものです。しかし、地域性から、フランチャイズごとに異なる味のピザを提供したい場合もあるでしょうから、フランチャイズにその地域の味を作る自由を認めることもまた重要です。

実装

Pizzeria のサブクラスは Create Pizza メソッドを実装することで作成するピザのフレーバーを決定します。

Pizza 抽象クラスの作成

/**
 * ピザ抽象クラス
 */
public abstract class Pizza {
 
 /**
 *  
 */
 String name;
 /**
 *  
 */
 String dough;
 /**
 *  
 */
 String sauce;
 /**
 *  
 */
 ArrayList<String> toppings = new ArrayList<>();
 
 void prepare() {
 System.out.println("Preparing " + name);
 System.out.println("Tossing dough...");
 System.out.println("Adding souce...");
 System.out.println("Adding toppings: ");
 for (int i = 0; i < toppings.size(); i++) {
 System.out.println(" "+ toppings.get(i));
 }
 }
 /**
 *  
 */
 void bake() {
 System.out.println("Bake for 25 minutes at 350");
 }
 
 /**
 *  
 */
 void cut() {
 System.out.println("Cutting the pizza into diagonal slices");
 }
 
 /**
 *  
 */
 void box() {
 System.out.println("Place pizza in official PizzaStore box");
 }
 
 public String getName() {
 return name;
 }
}

さまざまな味と種類のピザを作ることができます。

/**
 * ニューヨーク・スタイルのチーズ・ピザ
 */
public class NYStyleCheesePizza extends Pizza {
 public NYStyleCheesePizza() {
 name = "NY Style Sauce and Cheese Pizza";
 dough = "Thin Crust Dough";
 sauce = "Marinara Sauce";
 toppings.add("Grated Reggiano Cheese");
 }
}
/**
 * ニューヨーク・スタイルのクラム・ピザ
 */
public class NYStyleClamPizza extends Pizza {
 public NYStyleClamPizza() {
 name = "NY Style Sauce Clam Pizza";
 dough = "Thin Crust Dough";
 sauce = "Marinara Sauce";
 toppings.add("Fresh Clams");
 }
}
/**
 * シカゴ・スタイルのチーズ・ピザ
 */
public class ChicagoStyleCheesePizza extends Pizza {
 public ChicagoStyleCheesePizza() {
 name = "Chicago Style Deep Dish Cheese Pizza";
 dough = "Extra Thick Crust Dough";
 sauce = "Plum Tomato Sauce";
 toppings.add("Shredded Mozzarella Cheese");
 }
 
 void cut() {
 System.out.println("Cutting the pizza into square slices");
 }
}
/**
 * シカゴスタイルのクラムピザ
 */
public class ChicagoStyleClamPizza extends Pizza {
 public ChicagoStyleClamPizza() {
 name = "Chicago Style Clam Pizza";
 dough = "Extra Thick Crust Dough";
 sauce = "Plum Tomato Sauce";
 toppings.add("Frozen Clams");
 }
 
 void cut() {
 System.out.println("Cutting the pizza into square slices");
 }
}

Pizzeria抽象クラスの作成

/**
 * ピッツェリア抽象クラス
 */
public abstract class PizzaStore {
 
 /**
 * ピザを注文する
 */
 public Pizza orderPizza(String type) {
 Pizza pizza = createPizza(type);
 pizza.prepare();
 pizza.bake();
 pizza.cut();
 pizza.box();
 return pizza;
 }
 
 /**
 * ピザを作成する
 */
 protected abstract Pizza createPizza(String type);
}

さまざまな味のピッツェリアを創造

/**
 * ニューヨーク・スタイルのピッツェリア
 */
public class NYStylePizzaStore extends PizzaStore {
 @Override
 protected Pizza createPizza(String type) {
 Pizza pizza = null;
 if ("cheese".equals(type)) {
 pizza = new NYStyleCheesePizza(); 
 } else if ("clam".equals(type)) {
 pizza = new NYStyleClamPizza();
 }
 return pizza;
 }
}
/**
 * シカゴ風味のピッツェリア
 */
public class ChicagoStylePizzaStore extends PizzaStore {
 @Override
 protected Pizza createPizza(String type) {
 Pizza pizza = null;
 if ("cheese".equals(type)) {
 pizza = new ChicagoStyleCheesePizza(); 
 } else if ("clam".equals(type)) {
 pizza = new ChicagoStyleClamPizza();
 }
 return pizza;
 }
}

ピッツェリアの様々な味を使ったピザの注文

public class Test {
 
 public static void main(String[] args) {
 // ニューヨーク・スタイルのピッツェリア
 PizzaStore nyStore = new NYStylePizzaStore();
 // シカゴ風味のピッツェリア
 PizzaStore chicagoStore = new ChicagoStylePizzaStore();
 
 // チーズピザを注文する
 Pizza pizza = nyStore.orderPizza("cheese");
 System.out.println("Ethan ordered a " + pizza.getName() + "
");
 pizza = chicagoStore.orderPizza("cheese");
 System.out.println("Joel ordered a " + pizza.getName() + "
");
 }
}
Read next

スレッド同期ツールクラス

セマフォは、特定のリソースに同時にアクセスするスレッドの数を制御するために使用されます。そのため、特にデータベース接続のような共通リソースが限られているアプリケーションシナリオで、フロー制御に使用することができます。たとえば、何万ものファイルのデータを読み込む必要がある場合、それらはすべてIO集約的なタスクであるため、何十ものスレッドを起動して同時に読み込むことができます。

Jul 2, 2020 · 16 min read