Head First Java 设计模式——工厂方法模式

来源:互联网 发布:郑海霞wnba数据 编辑:程序博客网 时间:2024/05/12 14:09

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

        抽象工厂模式,提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

        书中给出的是一个Pizza店的例子。假设你有一个pizza店,你可能会这样定义你的预定菜单:

Pizza orderPizza() {Pizza pizza = new Pizza();pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}


        你可能需要更多的pizza类型,于是会这样定义

Pizza orderPizza(String type) {Pizza pizza; if(type.equals("cheese")) {pizza = new CheesePizza();} else if(type.equals("greek")) {pizza = new GreekPizza();} else if(type.equals("pepperoni")) {pizza = new PepperoniPizza();}pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}


        但是你以后可能又会增加或减少Pizza的类型,这时你就会发现哪些代码是会变的,哪些是不会变的。

        封装创建对象的代码,我们将创建对象移到orderPizza()之外。如下所示:

        我们称这个新对象为"工厂",orderPizza()就变成此对象的客户。接下来我们建立一个简单Pizza工厂

public class SimplePizzaFactory {public Pizza createPizza(String type) {Pizza pizza = null;if(type.equals("cheese")) {pizza = new CheesePizza();} else if(type.equals("greek")) {pizza = new GreekPizza();} else if(type.equals("pepperoni")) {pizza = new PepperoniPizza();} else if(type.equals("clam")) {pizza = new ClamPizza();} else if(type.equals("viggie")) {pizza = new ViggiePizza();} return pizza;}}

        然后我们重做PizzaStore类

public  class PizzaStore {SimplePizzaFactory factory;public PizzaStore(SimplePizzaFactory factory) {this.factory = factory;}Pizza orderPizza(String type) {Pizza pizza; pizza = factory.createPizza(type);pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}}

        接下来我们可能会有不同地方的加盟店,不同的加盟店口味又会有所不同,例如纽约加盟店跟芝加哥加盟店,这个时候你可能会想到为每个地方建议一个工厂分别为NYPizzaFactory、ChicagoFactory。如果你想要预定一个Pizza,你就要像如下调用:

NYPizzaFactory nyFactory = new NYPizzaFactory();PizzaStore nyStore = new PizzaStore(nyFactory);nyStore.orderPizza("Veggie");ChicagoPizzaFactory chicagoFactory = new ChicagoPizzaFactory();PizzaStore chicagoStore = new PizzaStore(chicagoFactory);chicagoStore.orderPizza("Veggie");


        但是在推广SimpleFactory时,加盟店采用你的工厂创建Pizza,但是其他部分,却开始采用他们自创的流程:烘烤的做法有些差异、不要切片、使用其他厂商的盒子。这时候,我们可以用工厂方法设计模式来解决问题,如下:

 

public abstract class PizzaStore {Pizza orderPizza(String type) {Pizza pizza; //把createPizza()方法从工厂对象移回PizzaStore。pizza = createPizza(type);pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}//把工厂对象移到这个方法中,作为一个抽象方法,允许子类自己实现这个方法,并保证了其他流程不被改变。protected abstract Pizza createPizza(String type);}


        开一家纽约加盟店

public class NYPizzaStore extends PizzaStore {Pizza createPizza(String item) {if(type.equals("cheese")) {pizza = new NYStyleCheesePizza();} else if(type.equals("greek")) {pizza = new NYStyleGreekPizza();} else if(type.equals("pepperoni")) {pizza = new NYStylePepperoniPizza();} else if(type.equals("clam")) {pizza = new NYStyleClamPizza();} }}

public abstract class Pizza {String name;String dough;String sauce;ArrayList<String> toppings = new ArrayList<String>();public 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));}};public void bake() {System.out.println("Bake for 25 minutes at 350");};public void cut() {System.out.println("Cutting the pizza into diagonal slices");};public void box() {System.out.println("Place pizza in official PizzaStore box");};}public class NYStyleCheesePizza extends Pizza {public NYStyleCheesePizza() {name = "NY Style Sauce and Cheese Pizza";doiugh = "Thin Crust Dough";sauce = "Marinara Sauce";toppings.add("Grated Reggiano Cheese");}}


 

PizzaStore nyPizzaStore = new NYPizzaStore();Pizza pizza = nyPizzaStore.orderPizza("cheese");


        所有工厂模式都是用来封装对象的创建。工厂方法模式通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。组成元素有:创造者类(PizzaStore)、产品类(Pizza)。

        接下来我们用抽象工厂模式,
        首先建造原料工厂。

public interface PizzaIngredientFactory {public Dough createDough();          //创建生面团  public Sauce createSauce();          //创建酱油    public Cheese createCheese();        //创建奶酪public Veggies[] createVeggies();    //创建蔬菜public Pepperoni createPepperoni();  //创建香肠public Clams createClam();           //创建蛤蚌}


        创建加盟店的原料工厂

public class NYPizzaIngredientFactory implements PizzaIngredientFactory {public Dough createDough() {return new ThinCrustDough();}public Sauce createSauce() {return new MarinaraSauce();}public Cheese createCheese() {return new ReggianoCheese();}public Veggies[] createVeggies() {Veggies veggies[] {new Garlic(), new Onion(), new Mushroom(), new RedPepper()};return veggies;}public Pepperoni createPepperoni() {return new SlicedPepperoni();}public Clams createClam() {return new FreshClams();}}


        重做Pizza

        class Pizza {String name;Dough dough;Sauce sauce;Veggies veggies[];Cheese cheese;Pepperoni pepperoni;Clams clam;abstract void prepare() {};public void bake() {System.out.println("Bake for 25 minutes at 350");};public void cut() {System.out.println("Cutting the pizza into diagonal slices");};public void box() {System.out.println("Place pizza in official PizzaStore box");};void setName(String name) {this.name = name;}}public class CheesePizza extends Pizza {PizzaIngredientFactory ingredientFactory;public CheesePizza(PizzaIngredientFactory factory) {this.ingredientFactory = factory;}void prepare() {System.out.println("Preparing " + name);dough = ingredientFactory.createDough();sauce = ingredientFactory.createSauce();cheese = ingredientFactory.createCheese();}}public class NYPizzaStore extends PizzaStore {protected Pizza createPizza(String item) {Pizza pizza = null;PizzaIngredientFactory ingredientFactory = new PizzaIngredientFactory();if(type.equals("cheese")) {pizza = new CheesePizza(ingredientFactory);pizza.setName("New York Style Cheese Pizza");} else if(type.equals("greek")) {pizza = new GreekPizza(ingredientFactory);pizza.setName("New York Style Greek Pizza");} else if(type.equals("pepperoni")) {pizza = new PepperoniPizza(ingredientFactory);pizza.setName("New York Style Pepperoni Pizza");} else if(type.equals("clam")) {pizza = new ClamPizza(ingredientFactory);pizza.setName("New York Style Clam Pizza");} }}PizzaStore nyPizzaStore = new NYPizzaStore();Pizza pizza = nyPizzaStore.orderPizza("cheese");//这里可能会传入错误的值导致错误,因此我们可以采用枚举类型作为参数。


 

设计原则:

1、要依赖抽象,不要依赖具体类。

2、倒置原则:变量不可以持有具体类的应用;不要让类派生自具体类;不啊哟覆盖基类中已实现的方法。