之前,我们讲了不算是设计模式的“简单工厂模式”,他将可变部分和固定部分进行分离,将对象的实例化封装到另一个类中,一定程度上减弱了扩展时带来的负面影响。接下来我们将叙述工厂方法。
首先,我们先讲下工厂模式的设计原则——依赖倒置原则:要依赖抽象,不要依赖具体类。这里说明了无论高层或低层组件都必须依赖于抽象。
依赖的意思:如果A的具体实现发生任何的改变都会影响B,那么B就依赖于A。所谓高层组件,是由其他低层组件定义其行为的类。在前例中,高层组件就是PizzaStore,低层组件就是Pizza。
在前例的基础上,我们需要对PizzaStore进行扩展,开设加盟店。
从SimplePizzaFactory出发,我们可以扩展出NYStorePizzaFactory,ChicagoPizzaFactory分别用来生产纽约风味,芝加哥风味的披萨。
NYPizzaFactory nyPizzaFactory = new NYPizzaFactory();//创建纽约风味的披萨制作工厂
NYPizzaStore nyStore = new PizzaStore(nyPizzaFactory);//建立一个披萨店,将披萨制作工厂作为参数
nyStore.orderPizza("veggie");
ChicagoPizzaFactory chicagoPizzaFactory = new ChicagoPizzaFactory();
ChicagoPizzaStore chicagoStore = new PizzaStore(chicagoPizzaFactory);
chicagoStore.orderPizza("veggie");
在这种情况下,我们每增加一个加盟店,新建一个Factory,但是前例中的固定部分(prepare(),bake(),cut(),box())却缺少了约束(顺序可能改变,可能缺少部分,也可能增加的部分)。我们希望通过建立一个框架增加一些质量控制。
public abstract class PizzaStore {
//createPizza()和orderPizza()放到一个框架里了
public Pizza orderPizza(String type){
Pizza pizza;
//这里pizza对象依然是抽象的,实现了解耦
pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
//工厂方法是抽象的
abstract Pizza createPizza(String type);
}
NYPizzaStore
public class NYPizzaStore extends PizzaStore {
@Override
Pizza createPizza(String type) {
if (type.equals("cheese")){
return new NYStyleCheesePizza();
}else if (type.equals("veggie")){
return new NYStyleVeggiePizza();
}else if (type.equals("clam")){
return new NYStyleClamPizza();
}else if (type.equals("pepperoni")){
return new NYStylePepperoniPizza();
}else {
return null;
}
}
}
ChicagoPizzaStore
public class ChicagoPizzaStore extends PizzaStore {
@Override
Pizza createPizza(String type) {
if (type.equals("cheese")){
return new ChicagoStyleCheesePizza();
}else if (type.equals("veggie")){
return new ChicagoStyleVeggiePizza();
}else if (type.equals("clam")){
return new ChicagoStyleClamPizza();
}else if (type.equals("pepperoni")){
return new ChicagoStylePepperoni();
}else {
return null;
}
}
}
产品类
public class Pizza {
String name;
String dough;
String sauce;
ArrayList toppings = new ArrayList();
void prepare(){
System.out.println("prepare" + name);
System.out.println("Tossing dough" + dough);
System.out.println("Adding sauce" + 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 minute 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 Cheese Pizza";
dough = "Extra Thick Crust Dough";
sauce = "Plam Tomato Sauce";
toppings.add("Shredded Mozzarella Cheese");
}
}
测试类:
public class PizzaTestDrive {
public static void main(String[] args) {
PizzaStore nyStore = new NYPizzaStore();
PizzaStore chicagoStore = new ChicagoPizzaStore();
Pizza pizza = nyStore.orderPizza("cheese");
System.out.println("Ethan ordered a " + pizza.getName() + "\n");
pizza = chicagoStore.orderPizza("veggie");
System.out.println("Joel ordered a " + pizza.getName() + "\n");
}
}
结果:
在工厂模式下,有两个组件:一是创建者类(PizzaStore),另一个是产品类(Pizza)。它们是平行的关系(因为它们都有抽象类,而抽象类都有许多具体的子类,每个子类都有自己的特定实现)。由此我们可以看到在普通工厂模式区别于简单工厂模式的一方面是:普通工厂模式不但抽象了产品类,还抽象了创建者类。
NYPizzaStore封装的是如何制作纽约风味的披萨,ChicagoPizzaStore封装的是如何制作芝加哥风味的披萨。工厂方法就是封装这种知识的关键所在。