作者:gnuhpc
出处:http://www.cnblogs.com/gnuhpc/
5.抽象工厂模式:
我们现在的场景是要在Pizza上采用不同的原料,针对不同的分店,首先我们先定义一个产生原料的工厂(抽象工厂类),我们有六种原料要供应:
public interface PizzaIngredientFactory {//抽象工厂的任务是定义一个负责创建一组产品的接口,在这个接口中的每个方法都负责创建一个具体的产品,利用抽象工厂的子类提供具体做法。
public Dough createDough();
public Sauce createSauce();
public Cheese createCheese();
public Veggies[] createVeggies();
public Pepperoni createPepperoni();
public Clams createClam();
}
(注:如果每个具体工厂类内部需要实现某种通用机制,这里就采用抽象类)
我们根据这一模式构建各地的分工厂(具体工厂类):
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
public Dough createDough() { {//采用工厂方法创建具体的产品
return new ThinCrustDough();
}
public Sauce createSauce() {
return new MarinaraSauce();
}
public Cheese createCheese() {
return new ReggianoCheese();
}
public Veggies[] createVeggies()
Veggies veggies[] = { new Garlic(), new Onion(), new Mushroom(), new RedPepper() };
return veggies;
}
public Pepperoni createPepperoni() {
return new SlicedPepperoni();
}
public Clams createClam() {
return new FreshClams();
}
}
现在我们就做一个pizza,使用原料工厂提供的原料,这是一个抽象产品类:
public abstract class Pizza {
String name;
Dough dough;
Sauce sauce;
Veggies veggies[];
Cheese cheese;
Pepperoni pepperoni;
Clams clam;
abstract void prepare(); //这个方法是要具体产品类实现,表示使用一族产品(这里指佐料)。
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");
}
void setName(String name) {
this.name = name;
}
String getName() {
return name;
}
public String toString() {
}
}
针对这一个基本的方式,我们构建具体的Pizza(这是具体产品类):
public class CheesePizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
public CheesePizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
void prepare() {
System.out.println("Preparing " + name);
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
}
}
接着,我们要在店面上进行抽象(抽象工厂类):
public abstract class PizzaStore {
protected abstract Pizza createPizza(String item);
public Pizza orderPizza(String type) {
Pizza pizza = createPizza(type);
System.out.println("--- Making a " + pizza.getName() + " ---");
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
在这个抽象的基础上我们开一家分店(具体工厂类):
public class NYPizzaStore extends PizzaStore {
protected Pizza createPizza(String item) {
Pizza pizza = null;
PizzaIngredientFactory ingredientFactory =
new NYPizzaIngredientFactory();
if (item.equals("cheese")) {
pizza = new CheesePizza(ingredientFactory);
pizza.setName("New York Style Cheese Pizza");
} else if (item.equals("veggie")) {
pizza = new VeggiePizza(ingredientFactory);
pizza.setName("New York Style Veggie Pizza");
} else if (item.equals("clam")) {
pizza = new ClamPizza(ingredientFactory);
pizza.setName("New York Style Clam Pizza");
} else if (item.equals("pepperoni")) {
pizza = new PepperoniPizza(ingredientFactory);
pizza.setName("New York Style Pepperoni Pizza");
}
return pizza;
}
}
现在我们试着订购一个Pizza:
public class PizzaTestDrive {
public static void main(String[] args) {
PizzaStore nyStore = new NYPizzaStore();
Pizza pizza = nyStore.orderPizza("cheese");
System.out.println("Ethan ordered a " + pizza + "/n");
}
}
抽象工厂方法提供了一个接口(此例中为PizzaIngredientFactory),用于创建相关或者依赖的对象家族,而不需要明确指定具体类,每个家族成员(此例为NYPizzaIngredientFactory)都负责创建一个具体的产品。与工厂方法的区别在于:工厂方法使用继承,针对的是类,利用工厂方法创建对象要扩展一个类,并覆盖它的工厂方法(例如这里的createPizza)——用来创建对象,工厂方法的实质在于通过子类创建对象;抽象工厂方法使用的是组合(ingredientFactory),针对的是一族对象,要使用这个工厂要首先将其实例化,然后将它传入一些针对抽象类型所写的代码中,优点在于可以把一群相关的产品集合起来,具体的工厂都是由工厂方法(prepare)创建的(这就是工厂方法和抽象工厂方法的联系)。在这个例子中商店的实现是采用的工厂方法,而制作Pizza的原料相关的类是采用的抽象工厂方法。
总结起来,这三者如下:
==========================
简单工厂方法中,
首先包括一个“抽象产品类”(该类可以是接口Interface,也可以是实际的类Class,本例中是Pizza),所有需要的产品类都是该“抽象产品类”的子类(如果是接口的话,那么就是说所有产品类都继承了该接口),本例中为各种XXPizza。
另外还包含一个具体的工厂类(本例为SimplePizzaFactory),所有需要的产品类都是该类生成的产品类对象。生成产品类的方法,其内部一般是类似于switch的结构,根据输入的标志,选择创建不同类型的对象。由于不知道创建的对象到底是哪个类的,所以方法的返回值的类型是“抽象产品类”。譬如,Pizza createPizza(String type),type就是一个标志,返回的是Pizza这个抽象产品类。
==========================
工厂方法中,
首先包括一个抽象产品类(本例中是Pizza),可以派生出多个具体产品类(本例为XXXPizza),这个和简单工厂方法没有区别。
另外还包含一个抽象工厂类(本例为PizzaStore),可以派生出具体工厂类(本例为XXXPizzaStore,这个与简单工厂方法中的具体工厂类没有区别), 每个具体工厂类(比如本例的ChicagoPizzaStore )可以根据输入标志创建一个具体产品类的实例。
较之简单工厂方法,工厂方法对于工厂类进行了抽象产生了一个抽象工厂类,通过这个抽象工厂类规定了一系列流程框架(orderPizza方法),另外,还将具体产品类的创建交给了具体的工厂类(createPizza在XXXPizza类中的实现)——也就是说,有多个具体工厂类相对应多个具体产品类,工厂类和产品类的耦合度下降。在本例中,如果不使用工厂方法,那么createPizza除了传入Pizza的类型还要传入商店的地点信息,譬如Chicago,这样的耦合度就会很大。
==========================
抽象工厂方法中,
首先,包括一个抽个产品类(本例中为Pizza),该抽象产品类可以派生出多个具体产品类(本例为XXXPizza),在每个具体产品类中以组合的形式将另一个抽象工厂类(本例为PizzaIngredientFactory )的引用包含进来,完成一群具体产品类的构建(XXXPizza的Prepare方法)。
另外还包含两个抽象工厂类,本例中PizzaStore,可以派生出多个具体工厂类XXXPizzaStore,这个与简单工厂方法中的具体工厂类没有区别, 每个具体工厂类可以创建一个具体产品类的实例(XXXPizza),但是这个具体产品类的实例比较特殊,是利用另一个抽象工厂类PizzaIngredientFactory 的具体工厂类创建的一群具体产品类而构建(XXXPizza的Prepare方法),请注意这个类才是抽象工厂方法的实质。
在线视频:http://v.youku.com/v_show/id_XMjU1NTkyNDU2.html
参考文献:http://www.cnblogs.com/lengjunming/archive/2011/01/13/1934830.html
作者:gnuhpc
出处:http://www.cnblogs.com/gnuhpc/