這應該是大家學design pattern第一個遇到的pattern吧,這個pattern有兩個角色
簡單說就是透過Factory來生產Product,client只需要告訴Factory,我要一個什麼Product,然後就得到他要的Product了。
架構圖長這樣:
我現在要去吃pizza了,所以需要定義:
當然都要是AbstractClass 或 interface,不應該把實作內容直接寫在這邊,物件導向語言的其中一個守則:針對介面寫程式,不是針對實踐方法寫程式
宣告Factory
public abstract class PizzaStore {
    public abstract Pizza createPizza(String type); 
    public Pizza orderPizza(String type) { // client只要呼叫這個method就好
        Pizza pizza = createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}
宣告Product
package com.example.designpattern.creational.factory_method.example2;
public abstract class Pizza {
    String name;
    String dough;
    String sauce;
    // method都不是宣告為abstract,如果subClass不用客製,就不用override
    void prepare() {
        System.out.println("Preparing: " + name + ", " + dough + ", " + sauce );
        System.out.println("Tossing dough...");
    };
    
    void bake() {
        System.out.println("Bake for 25 minutes at 350");
    }
    
    void cut() {
        System.out.println("Cutting pizza into diagonal slices");
    }
    
    void box() {
        System.out.println("Place pizza in official PizzaStore box");
    }
}
有了Factory跟Product後,就可以繼承他們來寫concreteClass了
先寫Factory,NYPizzaStore
package com.example.designpattern.creational.factory_method.example2;
public class NYPizzaStore extends PizzaStore {
    @Override
    public Pizza createPizza(String type) {
        Pizza pizza = null;
        
        // 這間PizzaStore可以生產兩種Pizza
        if("cheese".equals(type)) {
            pizza = new NYCheesePizza();
        } else if ("sausage".equals(type)) {
            pizza = new NYSausagePizza();
        }
        return pizza;
    }
    @Override
    public Pizza orderPizza(String type) {
        return super.orderPizza(type);
    }
}
再來是Product,第一種Product NYCheesePizza
package com.example.designpattern.creational.factory_method.example2;
public class NYCheesePizza extends Pizza {
    String name = "NYCheesePizza";
    String dough = "crispy";
    String sauce = "cheese sauce";
    @Override
    void prepare() {
        System.out.println("Amazing~~~ " + name +" , " + dough + " , " + sauce);
    }
    
    @Override
    void bake() {
        System.out.println("Bake for 15 minutes at 400");
    }
    
    @Override
    void cut() {
        System.out.println("Cutting pizza into 8 slices");
    }
}
第二種Prodcut NYSausaePizze
package com.example.designpattern.creational.factory_method.example2;
public class NYSausagePizza extends Pizza {
   String name = "NY Sausage pizze";
   String dough = "Thick";
   String sauce = "Marinara sauce";
    @Override
    void prepare() {
        System.out.println(name +" , " + dough + " , " + sauce);
    }
}
Client 要來點pizza了
package com.example.designpattern.creational.factory_method.example2;
public class PizzaClient {
    public static void main(String[] args) {
        // 進入NYPizzaStore
        PizzaStore pizzaStore = new NYPizzaStore();
        
        // 我要cheese pizza,啪,cheesePizza
        Pizza cheesePizza = pizzaStore.orderPizza("cheese");
        System.out.println("---------------");
        
        // 我要sausage pizza,啪,sausagePizza
        Pizza sausagePizza = pizzaStore.orderPizza("sausage"); 
    }
    /*
        output:
        Amazing~~~ NYCheesePizza , crispy , cheese sauce
        Bake for 15 minutes at 400
        Cutting pizza into 8 slices
        Place pizza in official PizzaStore box
        
        ---------------
        NY Sausage pizze , Thick , Marinara sauce
        Bake for 25 minutes at 350
        Cutting pizza into diagonal slices
        Place pizza in official PizzaStore box
     */
}
https://refactoring.guru/design-patterns/factory-method
https://www.oreilly.com/library/view/head-first-design/0596007124/