抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体的类。
抽象工厂运行客户使用抽象的接口来创建一组相关的产品,而不需要知道或关心实际产出的具体产品是什么,这样客户就从具体的产品中被解耦。
抽象工厂的任务是定义一个负责创建一组产品的接口。这个接口内的每个方法都负责创建一个具体产品。
设计原则:依赖抽象,不要依赖具体类
需求实例:不同的披萨加盟店利用本地区的原料工厂生成符合本地区消费习惯的披萨。主要的原料包括面团、酱料和芝士。
1、以接口的形式,定义一个生成这些原料的工厂
//如果每个工厂都有一种通用的方法,可以改为抽象类
public interface PizzaIngredientFactory {
//这些对象之间有一定的相关性,都是用于生成披萨
public Dough createDough();
public Sauce createSauce();
public Cheese createCheese();
}
2、不同地区的原料工厂都要实现该工厂
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
//产生每一种原料的实体
public Dough createDough() {
return new Dough();
}
public Sauce createSauce() {
return new Sauce();
}
public Cheese createCheese() {
return new Cheese();
}
}
3、使用配料工厂提供的配料制作不同口味的披萨,
3.1、重写披萨类,不同的加盟店需要根据不同配料工厂提供的配料制作不同披萨,所以在准备阶段,需要获取原料,这是每个加盟店都需要的流程:
public abstract class NewPizza {
//披萨原料
Dough dough;
Sauce sauce;
Cheese cheese;
//抽象类,获取不同的原料
abstract void prepare();
void bake(){
System.out.println("bake for 25 at 350");
}
void box(){
System.out.println("boxing now");
}
}
3.2、制作芝士口味的披萨(相当于由子类来实现具体的实例)
//Pizza类根本不关心这些原料是哪个工厂提供的,它只负责如何制作披萨
public class ChessPizza extends NewPizza {
PizzaIngredientFactory pif;
public ChessPizza(PizzaIngredientFactory pif){
this.pif=pif;
}
@Override
void prepare() {
//利用配料工厂获取不同的配料
dough=pif.createDough();
sauce=pif.createSauce();
cheese=pif.createCheese();
}
}
3.3、纽约加盟店需要制作一个芝士口味的披萨
public class NYNewPizzaStore extends PizzaStore {
@Override
protected NewPizza createPizza(String type) {
NewPizza npizza=null;
//指定一个配料工厂
PizzaIngredientFactory ingredientFactory=new NYPizzaIngredientFactory();
if(type.equals("cheese")){
npizza=new ChessPizza(ingredientFactory);
}
return npizza;
}
}
抽象工厂提供一个用来创建一个产品家族的抽象类型,把一群相关的产品集合起来,这个类型的子类定义了产品被产生的方法。要想使用这个工厂,必须先实例化它(导致抽象工厂的每个方法实际上看起来都像是工厂方法),然后将它传入一些针对抽象类型所写的代码中。
但是如果要扩展这组产品,那就需要修改接口。所以需要一个大的接口来创建整个产品家族。而工厂方法模式只是创建一个产品,不需要很大的接口,只需要一个方法就可以。
当需要创建产品家族和想让制造的相关产品集合起来,可以使用抽象工厂模式。