介绍
工厂方法模式引入工厂等级结构,解决了简单工厂模式中工厂类职责过重的问题,但由于工厂方法模式中每个工厂只创建一类具体类的对象,这将会导致系统当中的工厂类过多,这势必会增加系统的开销。此时,我们可以考虑将一些相关的具体类组成一个“具体类族”,由同一个工厂来统一生产,这就是我们本文要说的“抽象工厂模式”的基本思想。抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
实现
先定义一个抽象原料工厂:
public interface FoodFactory { Egg provideEgg(); Fruit provideFruit(); } 复制代码
每个店对应的具体工厂:
public class CenterFoodFactory implements FoodFactory { @Override public Egg provideEgg() { return new NormalEgg(); } @Override public Fruit provideFruit() { return new StrawberryFruit(); } } public class CollegeFoodFactory implements FoodFactory { @Override public Egg provideEgg() { return new SpecialEgg(); } @Override public Fruit provideFruit() { return new MongoFruit(); } }
具体的类:
public abstract class Cake { String name; Fruit fruit; Egg egg; abstract void prepare(); void bake(){ System.out.println("bake"); } void box(){ System.out.println("box"); } public String getName() { return name; } public Fruit getFruit(){ return fruit; } public Egg getEgg(){ return egg; } } public class CenterFruitCake extends Cake { public CenterFruitCake(){ name = ; } @Override public void prepare(){ FoodFactory foodFactory = new CenterFoodFactory(); fruit = foodFactory.provideFruit(); egg = foodFactory.provideEgg(); } } public class CollegeFruitCake extends Cake { public CollegeFruitCake(){ name = ; } @Override public void prepare(){ FoodFactory foodFactory = new CollegeFoodFactory(); fruit = foodFactory.provideFruit(); egg = foodFactory.provideEgg(); } } public class CenterCakeStore extends CakeStore { @Override protected Cake createCake(String type) { Cake cake = null; if ("cheese".equals(type)) { cake = new CenterCheeseCake(); } else if ("fruit".equals(type)) { cake = new CenterFruitCake(); } else if ("cream".equals(type)) { cake = new CenterCreamCake(); } return cake; } } public class CollegeCakeStore extends CakeStore { @Override protected Cake createCake(String type) { Cake cake = null; if ("cheese".equals(type)) { cake = new CollegeCheeseCake(); } else if ("fruit".equals(type)) { cake = new CollegeFruitCake(); } else if ("cream".equals(type)) { cake = new CollegeCreamCake(); } return cake; } }
客户端代码:
public class Client { public static void main(String[] args) { CakeStore cakeStore = new CollegeCakeStore();//这里可通过引入配置文件更改 cakeStore.orderCake("fruit"); } }
抽象工厂模式的优点与缺点:
优点:
- 易于交换产品系列,由于具体工厂类,在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。
- 它让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。
缺点:
- 在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,这是因为在抽象工厂角色中规定了所有可能被创建的产品集合,要支持新种类的产品就意味着要对该接口进行扩展,而这将涉及到对抽象工厂角色及其所有子类的修改,显然会带来较大的不便。
- 开闭原则的倾斜性。 (1) 增加产品族:对于增加新的产品族,抽象工厂模式很好地支持了“开闭原则”,只需要增加具体产品并对应增加一个新的具体工厂,对已有代码无须做任何修改。 (2) 增加新的产品等级结构:对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,违背了“开闭原则”。
适用情况
抽象工厂模式适用情况包括:一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节;系统中有多于一个的产品族,而每次只使用其中某一产品族;属于同一个产品族的产品将在一起使用;系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。