Fork me on GitHub

设计模式之工厂方法模式

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

  举个例子:开Pizza店

  为了满足面向对象村村民对比萨的向往,你决定开一家Pizza店。

  你的代码可能这样子写:

 

Pizza orderPizza(){
    Pizza pizza = new Pizza();
    
    pizza.prepare();//比萨制作的过程
    pizza.bake();
    pizza.cut();
    pizza.box();
    return 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(String type) {
    Pizza pizza;
    
    if(type.equals("cheese")) {//你有添加了Clam(蛤蜊比萨) Veggie(素食比萨)
        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("veggie")) {
        pizza = new VeggiePizza();
    }
    
}

  但是这样做明显违背了“开放封闭原则”,那么我们不如把创建比萨的代码移到另一个对象中,这个类专门来创建比萨。

  我们称它为简单工厂:

public class SimplePizzaFactory {
    public Pizza createPizza(String type) {//通过传入的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 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;
    }
}

   简单模式其实也不是一个设计模式,反而比较像是一种编程习惯。但由于经常被使用,所以我们给它一个“OO Pattern荣誉奖”。不要以为简单工厂不是一个“真正的”模式,就忽略它的用法。让我们来看看新的比萨店类图。

  

  由于经营有成,击败了各种竞争者,现在大家希望面向对象的比萨店能够在附近有加盟店。但是由于区域的差异,每家加盟店可能提供的口味不相同,比如说(纽约、芝加哥、加州)。因此为了满足不同区域的消费者的要求,现在需要重新安排我们的Pizza工厂。

  一个想法就是利用SimplePizzaFactory,写出三个不同的工厂,分别为NYPizzaFactory、ChicagoPizzaFactory、CaliforniaPizzaFactory。

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

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

  但是问题来了,每个加盟店都开始使用属于自己的一套制作pizza流程,因此我们需要给比萨店构造一个合适的框架:

public abstract class PizzaStore() {//现在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);//“工厂方法”也是抽象的
}

  我们需要让每一个加盟店自己决定自己的pizza制作流程,依旧是让子类来作出决定:

  

  

Public Pizza createPizza(type) {//纽约的pizza店创造属于自己的独特口味
    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();
    }else if(type.equals("veggie")) {
        pizza = new NYStyleVeggiePizza();
    }
}
Public Pizza createPizza(type) {//芝加哥的pizza店创造属于自己的独特口味
    if(type.equals("cheese")) {
        pizza = new ChicagoStyleCheesePizza();
    }else if(type.equals("greek")) {
        pizza = new ChicagoStyleGreekPizza();
    }else if(type.equals("pepperoni")) {
        pizza = new ChicagoStylePepperoniPizza();
    }else if(type.equals("clam")) {
        pizza = new ChicagoStyleClamPizza();
    }else if(type.equals("veggie")) {
        pizza = new ChicagoStyleVeggiePizza();
    }
}

  现在让我们开始加盟店:

public class NYPizzaStore extends PizzaStore {//纽约的pizza点
    Pizza createPizza(String item) {
        if(item.equals("cheese")){
            return new NYStyleCheesePizza();
        }else if(item.equals("veggie")){
            return new NYStyleVeggiePizza();
        }else if(item.equals("clas")){
            return new NYStyleClamPizza();
        }else if(item.equals("pepperoni")){
            return new NYStylePepperoniPizza();
        }else return null;
    }
}

   

public class ChicagoPizzaStore extends PizzaStore {//芝加哥的pizza店
    Pizza createPizza(String item) {
        if(item.equals("cheese")){
            return new ChicagoStyleCheesePizza();
        }else if(item.equals("veggie")){
            return new ChicagoStyleVeggiePizza();
        }else if(item.equals("clas")){
            return new ChicagoStyleClamPizza();
        }else if(item.equals("pepperoni")){
            return new ChicagoStylePepperoniPizza();
        }else return null;
    }
}

  声明一个工厂方法:

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 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 sauce...");
        System.out.println("Adding toppings: ");
        for(int i = 0 ; i < toppings.size(); i++ ){
            System.out.println("    "+toppings.get(i));
        }
    }
    
    void baek(){
        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 offical 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 Sauce";
        
        toppings.add("Grated Reggiano Cheese");
    }
}
public class ChicagoStyleCheesePizza extends Pizza {
    public ChicagoStyleCheesePizza(){
        name = "Chicago Style Deep Dish 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");
    }
}

  现在我们可以测试一下加盟店的运营情况了:

public class PizzaTestDrive(){
    
    public static void main(String[] args)    {
        PizzaStore nyStore = new NYPizzaStore();//纽约pizza店
        PizzaStore chicagoStore = new ChicagoPizzaStore();//芝加哥pizza店
        
        Pizza pizza = nyStore.orderPizza("cheese");
        System.out.println("I ordered a "+pizza.getName()+"\n");
        
        pizza = new chicagoStore.orderPizza("cheese");
        System.out.println("You ordered a "+pizza.getName()+"\n");
    }
}

 

  上面便是我们的工厂模式用途之一;现在我们正式介绍我们强大的工厂模式:

  

posted @ 2016-05-17 22:48  伊甸一点  阅读(398)  评论(0编辑  收藏  举报