目录:注意,此模式涉及的示例,来自于工厂模式笔记:工厂模式
抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类;
知识点的梳理:
抽象工厂使用对象组合:对象的创建被实现在工厂接口所暴露出来的方法中; 抽象工厂创建相关的对象家族,而不需要依赖它们的具体类;再回到比萨店。。。 现在我们需要确保每家加盟店使用的原料都是高质量的。现在打算建造一家生产原料的工厂,并将原料运送到各家加盟店。而对于纽约和芝加哥需要准备两组不同的原料; 所谓的原料只是大家都使用相同的产品,但是各个地区的制作方式却又各不相同; 建造原料工厂 注意,示例中出现的所有类,如果没有给出具体代码,就定义一个空实现即可;现在,我们要建造一个工厂来生产原料,这个工厂将负责创建各个加盟店所需要的各种原料。但不关心各个加盟店如何使用这些原料;
public interface PizzaIngredientFactory {
//在接口中,每个原料都有一个对应的方法创建该原料
publicDough createDough();
publicSauce createSauce();
publicCheese createCheese();
publicVeggies[] createVeggies();
publicPepperoni createPepperoni();
publicClams createClam();
}
要做的事情是: 为每个区域建造一个工厂。需要创建一个继承自PizzaIngredientFactory的子类来实现每一个创建方法;实现一组原料类供工厂使用,例如ReggianoCheese,RedPeppers,ThickCrust-Dough。这些类可以在合适的区域间共享;然后仍然需要将这一切组织起来,将新的原料工厂整合进旧的PizzaStore代码中; 创建纽约原来工厂//具体原料工厂必须实现这个接口,纽约原来工厂也不例外
public class NYPizzaIngredientFactoryimplements PizzaIngredientFactory {
@Override
public Dough createDough() {
return new ThinCrustDough();
}
@Override
public Sauce createSauce() {
return new MarinaraSauce();
}
@Override
public Cheese createCheese() {
return new ReggianoCheese();
}
@Override
public Veggies[] createVeggies() {
//对于蔬菜,以一个蔬菜数组为返回值。在这里我们是直接把蔬菜写死,仅仅是为了测试使用
Veggiesveggies[] = {new Garlic(),new Onion(),new Mushroom(),new RedPepper()};
returnveggies;
}
@Override
public Pepperoni createPepperoni() {
//切片的腊肠
return new SlicedPepperoni();
}
@Override
public Clams createClam() {
//新鲜的蛤蜊
return new FreshClams();
}
}
重做比萨 生产原来的工厂已经创建完毕,现在只需要重做比萨,好让它们只使用工厂生产出来的原料。先从抽象的Pizza类开始:public abstract class Pizza {
Stringname;
Doughdough;
Saucesauce;
Veggiesveggies[];//每个比萨都持有一组在准备时会用到的原料
Cheesecheese;
Clamsclam;
//现在把prepare()方法声明为抽象。在这个方法中,我们需要收集比萨所需的原料,而这些原料当然是来自原料工厂
abstract void prepare();
public void bake(){
System.out.println("Bake for 25 minutes at 350");
}
public void cut(){
System.out.println("Cutting the pizza into diagonal slices");
}
public void box(){
System.out.println("Place pizza in official PizzaStore box");
}
public void setName(Stringname){
this.name =name;
}
public String getName(){
returnname;
}
@Override
public String toString() {
return"Pizza [name=" +name + ", dough=" +dough +", sauce=" + sauce +", veggies=" + Arrays.toString(veggies)
+", cheese=" +cheese + ", clam=" +clam +"]";
}
}
继续重做比萨 现在已经有了一个抽象比萨,可以开始创建纽约和芝加哥风味的比萨了。此后,加盟店必需直接从工厂取得原料;public class CheesePizzaextends Pizza {
PizzaIngredientFactoryingredientFactory;
//要制作比萨,需要工厂提供原料。所以每个比萨类都需要构造器参数中得到一个工厂,并把这个工厂存储在一个实例变量中
public CheesePizza(PizzaIngredientFactoryingredientFacotry){
this.ingredientFactory =ingredientFacotry;
}
@Override
void prepare() {
//prepare()方法一步一步地创建芝士比萨,每当需要原料时,就跟工厂要
System.out.println("Preparing " + name);
dough =ingredientFactory.createDough();
sauce =ingredientFactory.createSauce();
cheese =ingredientFactory.createCheese();
}
}
然后是蛤蜊比萨public class ClamPizzaextends Pizza {
PizzaIngredientFactoryingredientFactory;
public ClamPizza(PizzaIngredientFactoryingredientFactory){
//蛤蜊比萨也需要原料工厂
this.ingredientFactory =ingredientFactory;
}
@Override
void prepare() {
//要做出蛤蜊比萨,prepare()方法就必须从本地工厂中取得正确的原料
System.out.println("Preparing "+name);
dough =ingredientFactory.createDough();
sauce =ingredientFactory.createSauce();
cheese =ingredientFactory.createCheese();
clam =ingredientFactory.createClam();
}
}
public class VeggiePizzaextends Pizza {
PizzaIngredientFactoryingredientFactory;
public VeggiePizza(PizzaIngredientFactoryingredientFacotry){
this.ingredientFactory =ingredientFacotry;
}
@Override
void prepare() {
System.out.println("Preparing " + name);
dough =ingredientFactory.createDough();
sauce =ingredientFactory.createSauce();
cheese =ingredientFactory.createCheese();
}
}
再回到比萨店public class NYPizzaStoreextends PizzaStore {
@Override
protected Pizza createPizza(Stringtype) {
Pizzapizza =null;
//纽约店会用到纽约比萨原料工厂,由该原料工厂负责生产所有纽约风味比萨所需要的原料
PizzaIngredientFactoryingredientFactory =new NYPizzaIngredientFactory();
if(type.equals("cheese")){
//把工厂传递给每一个比萨,以便比萨能从工厂中取得原料
pizza =new CheesePizza(ingredientFactory);
pizza.setName("New York style Cheese Pizza");
}else if(type.equals("veggie")){
pizza =new VeggiePizza(ingredientFactory);
pizza.setName("New York Style Veggie Pizza");
}else if(type.equals("clam")){
pizza =new ClamPizza(ingredientFactory);
pizza.setName("New York Style Clam Pizza");
}
returnpizza;
}
}
我们做了些什么? 引入了新类型的工厂,也就是所谓的抽象工厂,来创建比萨原料家族;通过抽象工厂所提供的接口,可以创建产品的家族,利用这个接口书写代码,我们的代码将从实际工厂解耦,以便在不同上下文中实现各式各样的工厂,制造出各种不同的产品;如:不同的区域,不同的操作系统,不同的外观及操作;因为代码从实际的产品中解耦了,所以我们可以替换不同的工厂来取得不同的行为; 订购比萨的流程 首先需要一个纽约比萨店: PizzaStore nyPizzaStore = new NYPizzaStore(); 有了比萨店之后,开始接受订单: nyPizzaStore.orderPizza("cheese"); orderPizza()方法首先调用createPizza()方法: Pizzapizza = createPizza("cheese"); 当createPizza()方法被调用时,开始设计原料工厂: Pizza pizza = new CheesePizza(nyIngredientFactory); 接下来需要准备比萨。一旦调用了prepare()方法,工厂将被要求准备原料:voidprepare(){
dough = factory.createDough();
sauce = factory.createSauce();
cheese = factory.createCheese();
}
最后,得到了准备好的比萨,orderPizza()就会接着烘烤,切片,装盒; 定义抽象工厂模式 抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道实际产出的具体产品是什么。这样,客户就从具体的产品中被解耦; 类图: 工厂方法是不是潜伏在抽象工厂里面? 抽象工厂的每个方法实际上看起来都像是工厂方法(如:createDough(),createSource()等)。每个方法都被声明成抽象,而子类的方法覆盖这些方法来创建某些对象;这很像工厂方法;其实,抽象工厂的方法经常以工厂方法的方式实现,抽象工厂的任务是定义一个负责创建一组产品的接口;这个接口内的每个方法都负责创建一个具体产品,同时我们利用实现抽象工厂的子类来提供这些具体的做法。所以,在抽象工厂中利用工厂方法实现生产方法是相当自然的做法; 比较工厂方法和抽象工厂
