设计模式之工厂模式

来源:互联网 发布:mysql count 性能优化 编辑:程序博客网 时间:2024/05/17 18:14
工作中,当我们需要一个对象的时候,一般我们都是直接new一个对象出来使用,那么new有什么不对劲吗?当使用new时,我们是在实例化一个具体类,而不是接口,我们已经知道代码绑着具体类会导致代码更脆弱,更缺乏弹性。其实,使用new并没有错,真正的问题是"改变"。针对接口编程,可以隔离掉以后系统可能发生的一大堆改变,如果针对接口编程,那么通过多态,它可以与任何新类实现改接口。而使用具体类时,一旦加入新的具体类,就必须改变代码。处于这种情况,工厂模式诞生了。
一.披萨商店
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;}
上面的代码是披萨店制作披萨的示例,这段代码通过type返回不同的披萨类型,不过当我们需要新加或者去掉一些披萨的时候,我们只能修改orderPizza的代码了。我们知道,我们应该将变化和不变的代码分离,所以我们需要把创建披萨对象的代码拿出来。
二.建立一个简单披萨工厂
public class PizzaStore{    SimplePizzaFactory factory;    public PizzaStore(SimplePizzaFactory factory){        this.factory = factory;    }    Pizza orderPizza(String type){        Pizza pizza = factory.createPizza(type);        pizza.prepare();        pizza.bake();        pizza.cut();        pizza.box();        return pizza;    }}

public class SimplePizzaFactory{    public Pizza createPizza(String type){        if(type.equals("cheese")){            pizza = new CheesePizza();        }else if(type.equals("greek")){            pizza = new GreekPizza();        }else if(type.equals("pepperoni")){            pizza = new PepperoniPizza();        }        return pizza;    }}
简单工厂有什么好处呢?看起来似乎只是把问题搬到另一个对象罢了,别忘了SimplePizzaFactory可以有许多的客户。虽然目前只看到orderPizza()方法使用,然而后续可能会有PizzaShopMenu等其他地方使用,所以把创建披萨的代码包装进一个类,当以后实现改变时,只需要修改这个类即可。简单工厂其实不是一个设计模式,反而比较像是一个编程习惯。
三.工厂方法
工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
我们看看如何用工厂方法模式修改我们的披萨商店
public abstract class PizzaStore {     public Pizza orderPizza(String type){          Pizza pizza;                          //调用创建对象的方法,其实是调子类的创建披萨方法           pizza = createPizza( type);           pizza.prepare();           pizza.bake();           pizza.cut();           pizza.box();           return pizza ;     }      //声明抽象方法创建披萨,由子类来实现这个方法     abstract Pizza createPizza(String type);}

纽约风味的披萨商店
public class NYPizzaStore extends PizzaStore{     @Override     Pizza createPizza(String type) {           if(type .equals("cheese" )){               return new NYStypeCheesePizza();          } else if (type .equals("veggie" )){               return new NYStyleVeggiePizza();          } else if (type .equals("clam" )){               return new NYStyleClamPizza();          }           return null ;     }}
其实工厂方法模式看起来还是非常简单的,只是声明一个抽象方法来创建对象,具体的创建对象操作交给子类来实现,由子类决定要实例化的类是哪一个。工厂方法模式能够封装具体类型的实例化。
如果只有一个工厂方法的实现类时,工厂方法模式有什么优点呢?尽管只有一个具体创建者,工厂方法模式依然很有用,因为它帮助我们将产品的实现从使用中解耦,如果增加产品或者改变产品的实现,工厂类都不会受影响。
简单工厂和工厂方法之间有什么差异呢?他们看起来很类似,差别在于,在工厂方法中,返回披萨的类是子类。子类的确看起来很想简单工厂,简单工厂把全部的事情在一个地方都处理完了,然而工厂方法却是创建一个框架,让子类决定要如何实现。比方说,在工厂方法中,orderPizza()方法提供了一般的框架,以便创建披萨,orderPizza()方法依赖工厂方法创建具体类,并制造出实际的披萨。可通过继承PizzaStore类,决定实际制造的披萨是什么。简单工厂的做法,可以将对象的创建封装起来,但是简单工厂不具备工厂方法的弹性,因为简单工厂不能变更正在创建的产品。
四.抽象工厂
现在,我们要建造一个工厂来生成原料,这个工厂将负责创建原料家族中的每一种原料。也就是说,工厂将需要生成面团,酱料,芝士等。开始先为工厂定义一个接口,这个接口负责创建所有的原料。
public interface PizzaIngredientFactory {     public Dough createDough();     public Sauce createSauce();     public Cheese createCheese();}
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {     @Override     public Dough createDough() {           return new ThinCrustDough();     }     @Override     public Sauce createSauce() {           return new MarinataSauce();     }     @Override     public Cheese createCheese() {           return new ReggiannoCheese();     }}

public abstract class Pizza {     String name;     Dough dough;     Sauce sauce;     Cheese cheese;     List<String> toppings = new ArrayList<String>();          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");     }}

public class NYStyleClamPizza extends Pizza{     PizzaIngredientFactory ingredientFactory;     public NYStyleClamPizza(PizzaIngredientFactory ingredientFactory){           this.ingredientFactory = ingredientFactory ;     }     public NYStyleClamPizza(){               }     @Override     void prepare() {          System. out.println("Preparing " +name );           dough = ingredientFactory.createDough();           sauce = ingredientFactory.createSauce();           cheese = ingredientFactory.createCheese();     }}

public class NYPizzaStore extends PizzaStore{     @Override     Pizza createPizza(String type) {          Pizza pizza = null;          PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();           if(type .equals("cheese" )){               pizza = new NYStypeCheesePizza(ingredientFactory );               pizza.setName( "New York Style Cheese Pizza");          } else if (type .equals("veggie" )){               pizza = new NYStyleClamPizza(ingredientFactory );               pizza.setName( "New York Style Veggie Pizza");          } else if (type .equals("clam" )){               pizza = new NYStyleClamPizza(ingredientFactory );               pizza.setName( "New York Style Clam Pizza");          }           return pizza ;     }}

我们对代码做了一连串的改变,我们引入新类型的工厂,也就是所谓的抽象工厂,来创建披萨原料家族。通过抽象工厂所提供的接口,可以创建产品的家族,利用这个接口书写代码,我们的代码将从实际工厂解耦。因为代码从实际的产品中解耦了,所以我们可以替换不同的工厂来取得不同的鱼腥味。
抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道实际产出的具体产品是什么。抽象工厂的方法经常以工厂方法的方式实现。
五.工厂方法和抽象工厂
工厂方法实现用的是继承,而抽象工厂是通过对象的组合。其实整个工厂方法模式,只不过就是通过子类来创建对象,用这种做法,客户只需要知道他们所使用的抽象类型就可以了,而由子类来负责决定具体类型。抽象工厂提供一个用来创建一个产品家族的抽象类型,这个类型的子类定义了产品被产生的方法,要想使用这个工厂,必须先实例化它,然后将它传入一个针对抽象类型锁写的代码中。所以抽象工厂可以把一群相关的产品集合起来。
对于抽象工厂,新增一个产品需要改变接口。
当你需要创建产品家族和想让制造的相关产品集合起来时,可以使用抽象工厂。
工厂方法可以把你的客户代码从需要实例化的具体类中解耦。或者如果你目前还不知道将来需要实例化哪些具体类时,可以使用工厂方法。
区别: 工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。
0 0