设计模式(五):抽象工厂方法(多个工厂方法的组合)
一、概述
抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。可以理解成是多个工厂方法的组合。
二、解决问题
在工厂方法模式中,我们的具体创建者每次使用都只能创建一个同类型的对象,假如我们现在需要的是多个不同类型的对象,工厂方法就满足不了需求了。这时我们可以把多个工厂方法组合到一个类,这就是抽象工厂模式,它就是专门用来创建多个产品,也可以说是创建产品家族的。
三、结构类图
四、成员角色
抽象工厂(AbstractFactory):客户端直接引用,由未实现的工厂方法组成,子类必须实现其工厂方法创建产品家族。
具体工厂(ConcreteFactory):实现抽象工厂接口,负责实现工厂方法,一个具体工厂可以创建一组产品。
抽象产品(AbstractProduct):产品家族的父类,由此可以衍生很多子产品。
具体产品(Product):衍生自抽象产品,由工厂方法直接创建。
五、应用实例
在工厂方法模式中,我们使用了开烧饼店例子,现在我们让我们继续开烧饼店,为了保证烧饼的质量,我们要统一生产工艺,还要对原料做统一供应,防止偷工减料的问题。我们就是使用抽象工厂方法来统一供应原材料的,一起来看看如何做到吧。
首先创建抽象工厂,也就是原材料工厂
package abstrfactorymethod.pattern; public interface IngredientFactory { public Dough createDough(); public Sauce createSauce(); public Vegetable createVegetable(); public Meat createMeat(); public Seafood createSeafood(); }
原材料工厂中涉及很多原材料产品,我们现在创建这些产品,先开始创建抽象产品
package abstrfactorymethod.pattern; //面粉 public interface Dough { public String getName(); }
package abstrfactorymethod.pattern; //配料 public interface Sauce { public String getName(); }
package abstrfactorymethod.pattern; //蔬菜 public interface Vegetable { public String getName(); }
package abstrfactorymethod.pattern; //肉 public interface Meat { public String getName(); }
package abstrfactorymethod.pattern; //海鲜 public interface Seafood { public String getName(); }
接着创建所需的具体产品
package abstrfactorymethod.pattern; public class DBDough implements Dough{ public DBDough(){ System.out.println("创建" + getName()); } public String getName() { return "东北面粉"; } }
package abstrfactorymethod.pattern; public class TomatoSauce implements Sauce{ public TomatoSauce(){ System.out.println("创建" + getName()); } public String getName() { return "番茄酱"; } }
package abstrfactorymethod.pattern; public class Onion implements Vegetable{ public Onion(){ System.out.println("创建" + getName()); } public String getName() { return "洋葱"; } }
具体原材料准备好了,我们就可以创建具体工厂了
package abstrfactorymethod.pattern; public class ShaobingIngredientFactory implements IngredientFactory{ public Dough createDough() { return new DBDough();//东北面粉 } public Meat createMeat() { return null;//暂时不用肉,该接口备用 } public Sauce createSauce() { return new TomatoSauce();//番茄酱 } public Seafood createSeafood() { return null;//暂时不用海鲜,该接口备用 } public Vegetable createVegetable() { return new Onion();//洋葱 } }
有了原材料工厂,可以着手做烧饼了,先创建抽象烧饼
package abstrfactorymethod.pattern; public abstract class Shaobing { //烧饼名称 public String name; //烧饼用的配料 public Sauce sauce; //面团 public Dough dough; //蔬菜 public Vegetable vegetable; //该方法在子类实现,创建所需的原材料 public abstract void prepare(); //烤烧饼 public void bake(){ System.out.println("Bake for 25 minutes at 350C"); } //切面团 public void cut(){ System.out.println("Cutting the dough into fit slices"); } //打包 public void box(){ System.out.println("Place shaobing into official box"); } }
创建具体烧饼
package abstrfactorymethod.pattern; //洋葱烧饼 public class OnionShaobing extends Shaobing{ //原材料 抽象工厂 IngredientFactory ingredientFactory; public OnionShaobing(){ ingredientFactory = new ShaobingIngredientFactory(); } @Override public void prepare() { System.out.println("洋葱烧饼开始准备原材料"); dough = ingredientFactory.createDough(); sauce = ingredientFactory.createSauce(); vegetable = ingredientFactory.createVegetable(); } }
烧饼一切准备就绪,可以开店了
package abstrfactorymethod.pattern; //广州烧饼店 public class GZShaobingStore extends ShaobingStore{ @Override public Shaobing createShaobing(String type) { Shaobing shaobing = null; if("onion".equals(type)){ shaobing = new OnionShaobing(); } return shaobing; } }
测试烧饼店运行情况
package abstrfactorymethod.pattern; public class TestShaobingStore { public static void main(String[] args){ //在广州开一个烧饼店 ShaobingStore gzStore = new GZShaobingStore(); //售出一个洋葱烧饼 gzStore.orderShaobing("onion"); } }
运行结果:
六、优点和缺点
1、优点
(1)、允许客户使用抽象的接口创建一组相关产品,而不需要知道(或者关心)产出的具体产品是什么,这样客户就可以从具体的产品中解耦出来。
(2)、一个具体工厂可以创建多个产品,与工厂方法模式相比,可以少产生具体工厂的类数量。
(3)、易于交换产品系列,只要更换具体工厂,就可以改变这个产品系列。
2、缺点
(1)、抽象工厂是使用组合的方式把工厂方法集合到一个类中,当新增一个产品家族成员时就要修改抽象工厂类及其下面的具体工厂类,所以它的扩展性比较差。
(2)、每新增一个产品子类都要创建一个类,当产品子类过多时会产生很多类,导致系统复杂性加大。
七、使用场合
1、当需要创建产品家族,或者需要想让创建的产品集合起来时使用。
2、当系列产品不固定,在以后可能会增加整个系列产品时使用。