[设计模式]工厂模式(2)——工厂方法

 简介

根据《head first 设计模式》所述,工厂模式共有三种:静态工厂方法、工厂方法、抽象工厂。本文介绍工厂方法。

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

注:工厂方法(抽象)用来处理对象的创建,并将这样的行为封装在子类中,以将超类和子类解耦。

具体形式如下:abstract Product factoryMethod(String type)

其中,abstract表示工厂方法是抽象的,因此依赖子类来处理对象的创建;Product表示工厂方法必须返回一个产品,超类中定义的方法,通常使用到工厂方法的返回值;factoryMethod表示工厂方法将客户(也就是超类中的代码,例如orderPizza())和实际创建具体产品的代码分隔开来;type表示工厂方法可能需要参数也可能不需要参数来指定索要的产品。

2、模式结构:包括创建者类(抽象创建者类和具体创建者类)和产品类(抽象产品类和具体产品类)。

3、具体实现(完整代码)

这里假设我们需要一个披萨系统,客户指定自己要吃的披萨种类,而每种披萨有不同的使用材料,即使使用相同的材料也是有差别的(比如说制造披萨的面团,有的是用厚的,有的是用薄的),具体的实现如下所述。

  • 抽象创建者类:定义一个抽象的工厂方法,让子类实现此方法制造产品。它通常会包含依赖于抽象产品的代码,而这些抽象产品由子类制造,创建者不需要真的知道在制造哪种具体产品。这里我们将PizzaStore作为抽象创建者类,因为可以有不同风格的披萨店,它们生产披萨的制作方法不同,因此披萨店是变动较大的部分,这里将它抽象出来,只要实现继承它的子类,就可以增加披萨店。
//披萨店
public abstract class PizzaStore{  
    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);
}
  • 具体创建者类:用来生产具体产品的类,这里指生产披萨的店,它实现超类中的工厂方法(本例中是createPizza()方法),用来制造产品。因为每个披萨店都有自己的PizzaStore子类,因此可以利用工厂方法(createPizza()方法)创建自己风味的披萨。
//纽约风味的披萨店
public class NYStylePizzaStore extends PizzaStore{
    public Pizza createPizza(String item){
        if(item.equals("cheese")){
            return new NYStyleCheesePizza();
        }else if(item.equals("pepperoni")){
            return new NYStylePepperoniPizza();
        }else if(item.equals("clam")){
            return new NYStyleClamPizza();
        }else if(item.equals("veggie")){
            return new NYStyleVeggiePizza();
        }else return null;
    }
}

//芝加哥风味的披萨店
public class ChicagoStylePizzaStore extends PizzaStore{
    public Pizza createPizza(String item){
        if(item.equals("cheese")){
            return new ChicagoStyleCheesePizza();
        }else if(item.equals("pepperoni")){
            return new ChicagoStylePepperoniPizza();
        }else if(item.equals("clam")){
            return new ChicagoStyleClamPizza();
        }else if(item.equals("veggie")){
            return new ChicagoStyleVeggiePizza();
        }else return null;
    }
}

//加利福尼亚风味的披萨店
public class CaliforniaStylePizzaStore extends PizzaStore{
    public Pizza createPizza(String item){
        if(item.equals("cheese")){
            return new CaliforniaStyleCheesePizza();
        }else if(item.equals("pepperoni")){
            return new CaliforniaStylePepperoniPizza();
        }else if(item.equals("clam")){
            return new CaliforniaStyleClamPizza();
        }else if(item.equals("veggie")){
            return new CaliforniaStyleVeggiePizza();
        }else return null;
    }
}
  • 抽象产品类:工厂生产的产品,对于本例来说就是披萨,即Pizza类。
//披萨,它是我们要生产的产品
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 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;
    }
}
  • 具体产品类:是所有待实现的最小的元素,对于本例来说,就是具体风味的皮塞,如纽约风味的芝士披萨,或者芝加哥风味的芝士披萨等。
//纽约风味的芝士披萨
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 Cheese Pizza";
        dough = "ChicagoStyleCheese Dough";
        sauce = "ChicagoStyleCheese Sauce";

        toppings.add("ChicagoStyleCheese Cheese");
    }

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

//加利福尼亚风味的芝士披萨
public class CaliforniaStyleCheesePizza extends Pizza{
    public CaliforniaStyleCheesePizza(){
        name = "California Style Deep Dish Cheese Pizza";
        dough = "California Dough";
        sauce = "California Sauce";

        toppings.add("California Cheese");
    }

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

测试代码:

public class PizzaTestDrive{
    public static void main(String[] args){
        PizzaStore nyStore = new NYStylePizzaStore();
        PizzaStore chicagoStore = new ChicagoStylePizzaStore();

        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');
    }
}

运行结果如下图所示:

 

4、工厂方法的优点:

  • 解耦:将产品的实现”(具体创建者类)使用”(具体使用者类)解耦,因此如果想要增加产品或者改变产品的实现,并不会对创建者有影响。
  • 具备较好的弹性和扩展性,如可以随意扩展或者更改具体产品类,即增加一个工厂或者修改一个工厂。

5、工厂方法的缺点:

  • 工厂使用太单一,一个工厂只能生产一种产品(披萨)

6、工厂方法和静态工厂方法的异同:

  • 工厂方法创建一个框架,让子类决定如何实现,比如本例中,orderPizza()方法提供了一般框架用来创建披萨,orderPizza()方法依赖工厂方法创建具体创建者类,并制造出实际的披萨。工厂方法具备较大的弹性,可以随意增加工厂。
  • 静态工厂方法把全部的事情在一个地方都处理完了(SimplePizzaFactory类中),且静态工厂方法不具备较好的弹性,不能变更正在创建的产品。

 

参考资料

[1] head first 设计模式

posted @ 2020-03-13 18:27  justDoIT&  阅读(228)  评论(0编辑  收藏  举报