[设计模式]工厂模式(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 设计模式