/*
* 工厂方法模式
* 定义了一个创建对象的接口,
* 但由子类决定要实例化的类是哪一个.
* 工厂方法让类把实例话推迟到子类.
*/


import java.util.ArrayList;

public class Factory {

     public static void main(String[] args) {
  PizzaStore nyStore = new NYPizzaStore();
  PizzaStore chicagoStore = new ChicagoPizzaStore();

  Pizza pizza = nyStore.orderPizza( "cheese");
  System.out.println( "Ethan ordered a " + pizza.getName() + "\n");

  pizza = chicagoStore.orderPizza( "cheese");
  System.out.println( "Joel ordered a " + pizza.getName() + "\n");
    }

}

// 这就是传说中的工厂
abstract class PizzaStore {
     // 定义pizza的整个制作流程
     public Pizza orderPizza(String type) {
  Pizza pizza;

  pizza = createPizza(type);

  pizza.prepare();
  pizza.bake();
  pizza.cut();
  pizza.box();

   return pizza;
    }

     // 正真的工厂方法,推迟到子类去实现
     protected abstract Pizza createPizza(String type);
}

// 具体的工厂
class NYPizzaStore extends PizzaStore {
     //具体的方法不一定就是参数实现,也可以没有参数
     protected Pizza createPizza(String item) {
   if (item.equals( "cheese")) {
       return new NYStyleCheesePizza();
  } else if (item.equals( "veggie")) {
       return new NYStyleVeggiePizza();
  } else
       return null;
    }
}

class ChicagoPizzaStore extends PizzaStore {
     protected Pizza createPizza(String item) {
   if (item.equals( "cheese")) {
       return new ChicagoStyleCheesePizza();
  } else if (item.equals( "veggie")) {
       return new ChicagoStyleVeggiePizza();
  } else
       return null;
    }
}

//产品的抽象类
abstract class Pizza {
     protected String name;
     protected String dough;
     protected String sauce;
    ArrayList<String> toppings = new ArrayList<String>();

     void prepare() {
  System.out.println( "Preparing" + name);
  System.out.println( "Tossing dough");
  System.out.println( "Adding sauce...");
  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;
    }
}

//具体的产品类
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");
    }
}

class ChicagoStyleCheesePizza extends Pizza {
     public ChicagoStyleCheesePizza() {
  name = "Chicago Style Sauce and 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");
    }
}

class NYStyleVeggiePizza extends Pizza {
     public NYStyleVeggiePizza() {
  name = "NY Style Sauce and Veggie Pizza";
  dough = "Thin Crust Dough";
  sauce = "Marinara Sauce";

  toppings.add( "Grated Reggiano Veggie");
    }
}

class ChicagoStyleVeggiePizza extends Pizza {
     public ChicagoStyleVeggiePizza() {
  name = "Chicago Style Sauce and Veggie Pizza";
  dough = "Extra Thick Crust Dough";
  sauce = "Plum Tomato Sauce";

  toppings.add( "Shredded Mozzarella Veggie");
    }

     void cut() {
  System.out.println( "Cutting the pizza into square slices");
    }
}