定义
- 抽象工厂模式提供了一个创建一系列相关或相互依赖对象的接口
- 无须指定具体类
类型
创建型
适用场景
- 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
- 强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码
- 提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现
优点
- 具体产品在应用层代码隔离,无须关心创建细节
- 将一个系列的产品族统一到一起创建
缺点
- 规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口
- 增加了系统的抽象性和理解难度
产品等级结构与产品族
在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法具有唯一性,一般情况下,一个具体工厂中只有一个或者一组重载的工厂方法。但是有时候我们希望一个工厂可以提供多个产品对象,而不是单一的产品对象,如一个电器工厂,它可以生产电视机、电冰箱、空调等多种电器,而不是只生产某一种电器。为了更好地理解抽象工厂模式,我们先引入两个概念:
(1) 产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
(2) 产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中,海尔电视机、海尔电冰箱构成了一个产品族。
产品等级结构与产品族示意图如图3所示:
在图3中,不同颜色的多个正方形、圆形和椭圆形分别构成了三个不同的产品等级结构,而相同颜色的正方形、圆形和椭圆形构成了一个产品族,每一个形状对象都位于某个产品族,并属于某个产品等级结构。图3中一共有五个产品族,分属于三个不同的产品等级结构。我们只要指明一个产品所处的产品族以及它所属的等级结构,就可以唯一确定这个产品。
当系统所提供的工厂生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构、属于不同类型的具体产品时就可以使用抽象工厂模式。抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形式。抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、更有效率。抽象工厂模式示意图如图4所示:
以上【作者: 刘伟 】
结构
- 同 工厂方法模式 角色组成是一致的: 抽象工厂、具体工厂、抽象产品、具体产品
代码实例
我们按上边的 产品等级结构与产品族 中的例子来实现
- 步骤:
- 创建电视和冰箱抽象产品
- 电视抽象类
/**
* 电视抽象类
*/
public abstract class Television {
//生产电视抽象方法
public abstract void produce();
}
- 冰箱抽象类
/**
* 冰箱抽象类
*/
public abstract class Refrigerator {
//生产冰箱抽象方法
public abstract void produce();
}
- 分别创建海尔冰箱,电视产品类和海信冰箱,电视产品类
- 海尔冰箱
/**
* 海尔冰箱类,继承冰箱抽象类,实现其抽象方法
*/
public class HaierRefrigerator extends Refrigerator{
@Override
public void produce() {
System.out.println("海尔冰箱生产完成。。");
}
}
- 海尔电视
/**
* 海尔电视类,继承电视抽象类,实现其抽象方法
*/
public class HaierTelevision extends Television{
@Override
public void produce() {
System.out.println("海尔电视生产完成。。");
}
}
- 海信冰箱
/**
* 海信冰箱类,继承冰箱抽象类,实现其抽象方法
*/
public class HisenseRefrigerator extends Refrigerator{
@Override
public void produce() {
System.out.println("海信冰箱生产完成。。");
}
}
- 海信电视
/**
* 海信电视类,继承电视抽象类,实现其抽象方法
*/
public class HisenseTelevision extends Television{
@Override
public void produce() {
System.out.println("海信电视生产完成。。");
}
}
- 创建抽象工厂
/**
* 电器抽象工厂
*/
public interface ElectricalAppliancesFactory {
//获得冰箱
Refrigerator getRefrigerator();
//获得电视
Television getTelevision();
}
- 创建海尔和海信工厂类
- 海尔工厂类
/**
* 海尔工厂类,实现抽象工厂
*/
public class HaierFactory implements ElectricalAppliancesFactory {
//获得海尔冰箱
public Refrigerator getRefrigerator() {
return new HaierRefrigerator();
}
//获得海尔电视
public Television getTelevision() {
return new HaierTelevision();
}
}
- 海信工厂类
/**
* 海信工厂类,实现抽象工厂
*/
public class HisenseFactory implements ElectricalAppliancesFactory {
//获得海信冰箱
public Refrigerator getRefrigerator() {
return new HisenseRefrigerator();
}
//获得海信电视
public Television getTelevision() {
return new HisenseTelevision();
}
}
- 模拟应用层
public class Test {
public static void main(String[] args) {
ElectricalAppliancesFactory appliancesFactory = new HaierFactory();
Refrigerator refrigerator = appliancesFactory.getRefrigerator();
Television television = appliancesFactory.getTelevision();
refrigerator.produce();
television.produce();
ElectricalAppliancesFactory appliancesFactory1 = new HisenseFactory();
Refrigerator refrigerator1 = appliancesFactory1.getRefrigerator();
Television television1 = appliancesFactory1.getTelevision();
refrigerator1.produce();
television1.produce();
}
}
执行结果
海尔冰箱生产完成。。
海尔电视生产完成。。
海信冰箱生产完成。。
海信电视生产完成。。
由以下类图我们可以看出,我们的应用层根本不用关心具体的是什么产品,我们只关心从对应的工厂中获取对应的产品就可以了,应用层和具体的产品是解耦的。添加一个新的产品族的时候是非常容易的,只需要添加一个新的工厂类实现抽象工厂,具体产品继承抽象产品,不需要修改既有内部代码,是符合开闭原则的。但是当我们在产品族中添加一个新的产品的时,就显得有些力不从心了,需要修改抽象工厂以及工厂类的内部结构,这是不符合开闭原则的。所以在我们使用的时候还要针对业务再三斟酌