提前总结:工厂模式的主要作用是封装变化,把经常变化的地方封装成一个类。这样可以避免重复,方便维护。使客户代码和实现代码解耦,客户在实例化对象时,依赖于接口,而不是具体的实现类。
问题的引出:假如你有一家披萨店,你只会做一种披萨
public class PizzaStore{
public Pizza orderPizza(){
Pizza pizza = new Pizza();
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
后来你学会做多种披萨可供选择,修改orderPizza()
Pizza orderPizza(String type){
Pizza pizza;
if(type.equals("cheese")){
pizza = new CheesePizza();
}else if (type.equals("pepperoni")){
pizza = new PepperoniPizza();
}else if (type.equals("clam")){
pizza = new ClamPizza();
}else if (type.equals("veggie")){
pizza = new VeggiePizza();
}
}
但是这时候发现,每当学会一种披萨准备加进去的时候,都要修改orderPizza(),其实这是可以优化的,比如把主要发生变化的提出出来,单独的放在一个类中,这个方式又叫简单工厂:
一、简单工厂:可以创建原味披萨、蔬菜披萨等。比起都在PizzaSore中实现,简单工厂把披萨的创建封装起来,这样每次变化的时候就不用修改PizzaSore类了,而且还可以同时为多个PizzaStore提供服务。可以想象成把自己的披萨店分成两部分,一个是店面,一个是披萨加工工厂,而且这个工厂可以承接其他店面的订单。
public class PizzaStore{
SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory){
this.factory factory;
}
public Pizza orderPizza(String type){
Pizza pizza;
pizza = factory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
public class SimplePizzaFactory{
public Pizza createPizza(String type){
Pizza pizza = null;
if(type.equals("cheese")){
pizza = new CheesePizza();
}else if (type.equals("pepperoni")){
pizza = new PepperoniPizza();
}else if (type.equals("clam")){
pizza = new ClamPizza();
}else if (type.equals("veggie")){
pizza = new VeggiePizza();
}
return pizza;
}
}
店面生意很火爆,想开分店了怎么办,这时候要有一个统一的模式,所有的店和工厂共同遵守。把店面和工厂都抽象出来。每个店都有自己一系列的工厂。每个工厂只做一种披萨:
二、工厂模式
public abstract class PizzaStore{
public Pizza orderPizza(String type){
Pizza pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
abstract Pizza createPizza(type);
}
public class NYPizzaStore extends PizzaStore{
Pizza createPizza(String item){
if(item.equals("cheese")){
return new NYStyleCheesePizza();
}else if(item.equals("veggie")){
return new NYStyleVeggiePizza();
}else if(item.equals("clam")){
return new NYStyleClamPizza();
}else if(item.equals("pepperoni")){
return new BYStylePepperoniPizza();
}else return null;
}
public abstract class Pizza(){
String name;
String dough;
String sauce;
ArrayList toppings = new ArrayList();
void prepare(){
System.out.println("Preparing " + name);
System.out.println("Tossing dough... " );
System.out.println("Adding sause... " );
System.out.println("Adding toppings: " );
for(int i=0; i<topings.size();i++){
System.out.pringtln(" " + toppings.get(i));
}
void bake(){
System.out.println("Bake for 25 minutes at 350 " );
}
void cut(){
System.out.println("Cutting the pizza into diagonal slicees " );
}
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 Sause";
toppings.add("Grated Reggiano Cheese");
}
}
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(){ //覆盖了cut()方法,将pizza切成正方形
System.out.println("Cutting the pizza into square slices");
}
}
public class PizzaTestDrive{
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");
}
}
总结工厂模式:这里的抽象店面和工厂只是起到行为规范的作用,大家都遵循相同的步骤做事。
设计模式有个很重要的设计原则:要依赖抽象,不要依赖具体,很明显,工厂模式的店面依赖于工厂的具体实现。观察工厂模式的工厂,每个店面都各自拥有一套自己的工厂,很浪费,完全可以整合成一个系列的工厂,这个系列的工厂需要一个管理部门,里面设小组对接原来的各个工厂。实际操作时,原来相对于每个店面的工厂就成了一个整理需求的部门,不做生产工作,而是直接把店面的需求传递给真正工厂的管理部门的小组。
三、抽象工厂
public interface PizzaIngredientFacory{ //工厂的管理部门
public Dough createDough();
public Sauce createSauce();
public Cheese createSause();
public Veggies[] createVeggies();
public Pepperoni createPepperoni();
public Clams createClam();
}
public class NYPizzaIngredientFactory implements PizzaIngredientFactory{ //对接纽约店面的小组,这里放着纽约店面的具体需求
public Dough createDough(){
return new ThinCrustDough();
}
public Sauce createSause(){
return new MarinaraSause();
}
public Cheese createCheese(){
return new ReggianoCheese();
}
public Veggies[] createVeggies(){
Veggies veggies[] = {new Gralic(), new Onion(), new Mushroom()};
return veggies;
}
public Pepperoni createPepperoni(){
return new SlicedPepperoni();
}
public Clams createClam(){
return new FreshClams();
}
}
public abstract class Pizza{
String name;
Dough dough;
Sauce sauce;
Veggies veggies[];
Cheese cheese;
Pepperoni pepperonni;
Clams clam;
abstract void prepare();
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");
}
void setName(String name){
this.name = name;
}
String getName(){
return name;
}
public String toString(){}
}
public class CheesePizza extends Pizza{ //真正的生产工厂
PizzaIngredientFactory ingredientFactory;
public CheesePizza(PizzaIngredientFactory ingredientFactory){
this.ingredientFactory = ingredientFactory;
}
void prepare(){
System.out.println("Preparing " + name);
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
}
}
public class NYPizzaStore extends PizzaStore{ //对接店面的工厂,用来调用真正生产工厂的管理部门
pretected Pizza createPizza(String item){
Pizza pizza = null;
PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
if (item.equals("cheese")){
pizza = new CheesePizza(ingredientFactory);
pizza.setName("New York Style Cheese Pizza");
}else if (item.equals("veggie")){
pizza = new VeggiePizza(ingredientFactory);
pizza.setName("New York Style Veggie Pizza");
}else if (item.equals("clam")){
pizza = new ClamPizza(ingredientFactory);
pizza.setName("New York Style Clam Pizza");
}else if (item.equals("pepperoni")){
pizza = new PepperoniPizza(ingredientFactory);
pizza.setName("New York Style Pepperoni Pizza");
}
return pizza;
}
}
虽然把工厂模式改变成抽象工厂模式,但是客户代码PizzaTestDrive并没有发生任何变化!变化是披萨的生产方式,原来由直接和店面对接的工厂生产,现在变成和店面对接的工厂调用实际的工厂生产,传入的参数是接口,然后由实际的工厂调用接口的方法。