总的说来,工厂模式有两种:工厂方法和抽象工厂。
工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化方法推迟到子类。利用工厂方法创建对象,通常需要继承一个类,并覆盖它的工厂方法。
举例如下(还是来自《Head First 设计模式》中的例子):
1.工厂方法
现在我们要买一个NY风味的Cheese Pizza,那么首先要得到一个生产NY风味的Pizza的工厂,然后点菜(传入需要的风味名称:”cheese“)
PizzaStore nyStore = new NYPizzaStore();
Pizza pizza1 = nyStore.orderPizza("cheese");
abstract Pizza creatPizza(String type)
根据传入的参数,生产相应类型的Pizza。PizzaStore定义如下:
import edu.zju.www.Product.Pizza;;
public abstract class PizzaStore {
protected abstract Pizza creatPizza(String type); //这里提供了一个接口,让子类实现。从而到达了让子类去决定实例化类型的目的!
public Pizza orderPizza(String type){
Pizza pizza ;
pizza = creatPizza(type);
pizza.prepare();
pizza.cut();
pizza.box();
return pizza;
}
}
public Pizza creatPizza
其定义如下:
public class NYPizzaStore extends PizzaStore {
@Override
public Pizza creatPizza(String item) { //这里是具体生产的方法,为了简单起见,只生产一种风味cheese
// TODO Auto-generated method stub
if(item.equals("cheese")){
return new NYStyleCheesePizza();
}else
return null;
}
}
产品是Pizza。
Pizza的定义如下:
import java.util.ArrayList;
public abstract class Pizza {
String name;
String dough;
String sauce;
ArrayList topping = new ArrayList();
public 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 < topping.size();i++){
System.out.println(" " + topping.get(i));
}
}
public void bake(){
System.out.println("baking at 350");
}
public void cut(){
System.out.println("cutting the pizza into dialognal slices");
}
public void box(){
System.out.println("Place the pizza into box");
}
public String getName(){
return name;
}
}
NY风格的CheesePizza继承自Pizza,定义如下:public class NYStyleCheesePizza extends Pizza {
public NYStyleCheesePizza(){
name = "NY Syle Sauce and Cheese Pizza";
dough = "Thin Crust Dough";
sauce = "Marina Sauce";
topping.add("Grated Regginao Cheese");
}
}
preparing NY Syle Sauce and Cheese Pizza
Tossing dough...
Adding sauce...
Adding toppings:
Grated Regginao Cheese
cutting the pizza into dialognal slices
Place the pizza into box
2.抽象工厂
通过抽象工厂所提供的接口,可以创建产品的家族而不要指定具体的类。(抽象工厂提供的接口,就是为子类搭好了框架,所以所有的子类看起来本质上都一样,只是表现形式不一样。)
假设,生产Pizza需要3种原料:Dough, Sauce, Cheese。那么,就可以定义一个抽象工厂:PizzaIngredientFactoy
public interface PizzaIngredientFactoy {
public Dough createDough();
public Sauce createSauce();
public Cheese createCheese();
}
public class NYPizzaIngredientFactoty implements PizzaIngredientFactoy {
@Override
public Dough createDough() {
// TODO Auto-generated method stub
return new DoughNY();
}
@Override
public Sauce createSauce() {
// TODO Auto-generated method stub
return new SauceNY();
}
@Override
public Cheese createCheese() {
// TODO Auto-generated method stub
return new CheeseNY();
}
}
这回Pizza的类定义如下:
public abstract class Pizza {
Dough dough;
Sauce sauce;
Cheese cheese;
public abstract void prepare();
}
注意CheesePizza类使用了一个常用的手法:组合
public class CheesePizza extends Pizza {
PizzaIngredientFactoy ingredientFactory; //注意这里!!!!使用了组合
public CheesePizza(PizzaIngredientFactoy ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
@Override
public void prepare() {
// TODO Auto-generated method stub
System.out.println("Preparing.... ");
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
}
}
相同点:
工厂方法与抽象工厂都负责对象的创建,都是力图将类型的定义延迟到子类中(由子类来决定创建的类型)
不同点:
工厂方法使用继承,而抽象工厂使用组合:
可以看到,具体产品CheesePizza类中有一个Factory;
而在工厂方法中,要创建CheesePizza,首先要在外面自己创造一个Factory,然后调用工厂的创建方法并传入参数。