1 定义:
抽象工厂模式(Abstract Factory)
Provide an interface for creating families of related or dependent objects without specifying their concrete classes.(为创建一组相关或相互依赖的对象提供一个接口,而且无需指定它们的具体类。)
1.1 通用类图:
主要类图-1
更体现抽象工厂实质的类图及说明
(1).AbstractFactory:声明一个创建抽象产品对象的接口。
(2).CreateFactory:实现创建具体产品对象的操作。
(3).AbstractProduct:为一类产品对象声明接口。
(4).CreateProduct:定义一个将被相应具体工厂创建的产品对象,以实现AbstractProduct接口。
(5).仅使用AbstractFactory和AbstractProduct类声明的接口。
1.2 通用代码:
抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。我们来看看抽象工厂的通用源代码,首先有两个互相影响的产品线(也叫做产品族,产品种类),例如汽车的左侧门和右侧门,这两个应该是数量相等的——两个对象之间的约束,每个型号的车门都是不一样的,这是产品等级结构约束的。
类图如下:
- public abstract class AbstractProductA {
- //每个产品共有的方法
- public void shareMethod(){
- }
- //每个产品相同方法,不同实现
- public abstract void doSomething();
- }
- public abstract class AbstractProductB {
- //每个产品共有的方法
- public void shareMethod(){
- }
- //每个产品相同方法,不同实现
- public abstract void doSomething();
- }
- public class ProductA_Level_1 extendsAbstractProductA {
- @Override
- public void doSomething() {
- System.out.println("产品A等级1的实现方法");
- }
- }
- public class ProductA_Level_2 extendsAbstractProductA {
- @Override
- public void doSomething() {
- System.out.println("产品A等级2的实现方法");
- }
- }
- public class ProductB_Level_1 extendsAbstractProductB {
- @Override
- public void doSomething() {
- System.out.println("产品B等级1的实现方法");
- }
- }
- public class ProductB_Level_2 extendsAbstractProductB {
- @Override
- public void doSomething() {
- System.out.println("产品B等级2的实现方法");
- }
- }
- public abstract class AbstractCreator {
- //创建A产品家族
- public abstract AbstractProductA createProductA();
- //创建B产品家族
- public abstract AbstractProductB createProductB();
- }
- public class Creator_Level_1 extends AbstractCreator {
- //只生产产品等级为1的A产品
- public AbstractProductA createProductA() {
- return new ProductA_Level_1();
- }
- //只生产铲平等级为1的B产品
- public AbstractProductB createProductB() {
- return new ProductB_Level_1();
- }
- }
- public class Creator_Level_2 extendsAbstractCreator {
- //只生产产品等级为2的A产品
- publicAbstractProductA createProductA() {
- return new ProductA_Level_2();
- }
- //只生产铲平等级为2的B产品
- public AbstractProductB createProductB() {
- return new ProductB_Leve
2 优点
2.1 封装性
每个产品的实现类不是高层模块要关心的,它要关心的是:接口,抽象,它不关心对象是如何创建出来的,这是由工厂类创建的,只要知道工厂类是谁,我就能创建出一个需要的对象,省时省力。
2.2 产品族内的约束为非公开状态。
在抽象工厂模式中应该有这样一个约束:约束不同等级产品的生产比例。而这样的生产过程对调用工厂类的高层模式来说是透明的,它不需要知道这个约束,它就是要一个这样的产品,具体的产品族内的约束是在工厂内实现的。
3 缺点
抽象工厂模式的最大缺点就是产品族扩展非常困难,为什么这么说呢?我们以通用代码为例,如果要增加一个产品C,也就是说有产品家族由原来的2个,增加到3个,看看我们的程序有多大改动吧!抽象类AbstractCreator要增加一个方法createProductC(),然后,两个实现类都要修改,想想看,这在项目中的话,还这么让人活!严重违反了开闭原则,而且我们一直说明抽象类和接口是一个契约,改变契约,所有与契约有关系的代码都要修改,这段代码叫什么?叫“有毒代码”,——只要这段代码有关系,就可能产生侵害的危险!
4 应用场景
抽象工厂模式的使用场景定义非常简单: 一个对象族(或是一组没有任何关系的对象)都有相同的约束 ,则 可以使用抽象工厂模式 ,什么意思呢?例如一个文本编辑器和一个图片处理器,都是软件实体,但是*nix下的文本编辑器和WINDOWS下的文本编辑器虽然功能和界面都相同,但是代码实现是不同的,图片处理器也是类似情况,也就是具有了共同的约束条件:操作系统类型,于是我们可以使用抽象工厂模式,产生不同操作系统下的编辑器和图片处理器。
5 注意事项
在上述缺点论述中,提到抽象工厂模式的产品族扩展比较困难,但是要清楚是产品族扩展困难,而不是产品等级。在该模式下,产品等级是非常容易扩展的,增加一个产品等级,只要增加一个工厂类负责新增加出来的产品生产任务即可。也就是说横向<产品等级>扩展容易,纵向<产品族>扩展困难。从横向扩展上来讲,抽象工厂模式还是符合开闭原则的。
6 扩展
6.1 抽象工厂模式与工厂方法模式的区别
抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。
他与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。
在抽象工厂模式中,有一个产品族的概念:所谓的产品族,是指位于不同产品等级结构中功能相关联的产品组成的家族。抽象工厂模式所提供的一系列产品就组成一个产品族;而工厂方法提供的一系列产品称为一个等级结构 。
我们拿生产汽车的例子来说明他们之间的区别。
在上面的类图中,两厢车和三厢车称为两个不同的等级结构;而2.0排量车和2.4排量车则称为两个不同的产品族。再具体一点,2.0排量两厢车和2.4排量两厢车属于同一个等级结构,2.0排量三厢车和2.4排量三厢车属于另一个等级结构;而2.0排量两厢车和2.0排量三厢车属于同一个产品族,2.4排量两厢车和2.4排量三厢车属于另一个产品族。
明白了等级结构和产品族的概念,就理解工厂方法模式和抽象工厂模式的区别了,如果工厂的产品全部属于同一个等级结构,则属于工厂方法模式;如果工厂的产品来自多个等级结构,则属于抽象工厂模式。在本例中,如果一个工厂模式提供2.0排量两厢车和2.4排量两厢车,那么他属于工厂方法模式;如果一个工厂模式是提供2.4排量两厢车和2.4排量三厢车两个产品,那么这个工厂模式就是抽象工厂模式,因为他提供的产品是分属两个不同的等级结构。当然,如果一个工厂提供全部四种车型的产品,因为产品分属两个等级结构,他当然也属于抽象工厂模式了。
7 范例
7.1 华为 高低端手机
(高低等级、功能机智能机)
类图如下:
- package _03_AbstractFactory;
- public interface Phone {
- //获取手机类别
- public void getKind();
- //获取手机功能特性
- public void getFunctions();
- //获取手机等级
- public void getLevel();
- }
- public abstract class AbstractFeaturePhone implements Phone{
- public void getKind() {
- System.out.println("我是功能机! ");
- }
- public void getFunctions() {
- System.out.println("我只有有限的功能!");
- }
- }
- public class FPhone_Level_High extends AbstractFeaturePhone{
- @Override
- public void getLevel() {
- System.out.println("高端机");
- }
- }
- public class FPhone_Level_Low extends AbstractFeaturePhone{
- @Override
- public void getLevel() {
- System.out.println("低端机");
- }
- }
- public abstract class AbstractSmartPhone implements Phone{
- public void getKind() {
- System.out.println("我是智能机! ");
- }
- public void getFunctions() {
- System.out.println("我有无限多的功能!");
- }
- }
- public class SPhone_Level_High extends AbstractSmartPhone{
- @Override
- public void getLevel() {
- System.out.println("高端机");
- }
- }
- public class SPhone_Level_Low extends AbstractSmartPhone{
- @Override
- public void getLevel() {
- System.out.println("低端机");
- }
- }
- public abstract class PhoneFactory {
- public abstract Phone createFeaturePhone();
- public abstract Phone createSmartPhone();
- }
- public class Creator_Level_High extends PhoneFactory{
- public Phone createFeaturePhone(){
- return new FPhone_Level_High();
- }
- public Phone createSmartPhone() {
- return new SPhone_Level_High();
- }
- }
- public class Creator_Level_Low extends PhoneFactory{
- public Phone createFeaturePhone(){
- return new FPhone_Level_Low();
- }
- public Phone createSmartPhone() {
- return new SPhone_Level_Low();
- }
- }
- public class Client {
- public static void main(String[] args) {
- //第一条产线,产高端机
- PhoneFactory pfh = new Creator_Level_High();
- //第二条产线,产高端机
- PhoneFactory pfl = new Creator_Level_Low();
- Phone sh = pfh.createSmartPhone();
- sh.getLevel();
- sh.getKind();
- sh.getFunctions();
- Phone fl = pfl.createFeaturePhone();
- fl.getLevel();
- fl.getKind();
- fl.getFunctions();
- }
- }
结果:
高端机
我是智能机!
我有无限多的功能!
低端机
我是功能机!
我只有有限的功能!
7.2 选择组装电脑的配件
装机工程师要组装电脑对象,需要一系列的产品对象,比如CPU、主板等,于是创建一个抽象工厂给装机工程师使用,在这个抽象工厂里面定义抽象的创建CPU和主板的方法,这个抽象工厂就相当于一个抽象的装机方案,在这个装机方案里面,各个配件是能够相互匹配的。
每个装机的客户,会提出他们自己的具体装机方案,或者是选择已有的装机方案,相当于为抽象工厂提供了具体的子类,在这些具体的装机方案类里面,会创建具体的CPU和主板实现对象。
1、先看看CPU和主板的接口
CPU接口定义的示例代码如下:
- /**
- * CPU的接口
- * @author FX_SKY
- *
- */
- public interface CPUApi {
- /**
- * 示意方法,CPU具有运算的功能
- */
- public void calculate();
- }
主板接口定义的示例代码如下:
- /**
- * 主板的接口
- * @author FX_SKY
- *
- */
- public interface MainBoardApi {
- /**
- * 示意方法,主板都具有安装CPU的功能
- */
- public void installCPU();
- }
2、具体的CPU实现
Intel CPU实现示例代码如下:
- /**
- * Intel 的 CPU实现
- * @author FX_SKY
- *
- */
- public class IntelCPU implements CPUApi {
- /**
- * CPU的针脚数目
- */
- private int pins = 0;
- /**
- * 构造方法,传人CPU的针脚数目
- * @param pins
- */
- public IntelCPU(int pins) {
- this.pins = pins;
- }
- @Override
- public void calculate() {
- System.out.println("now in Intel CPU,pins="+pins);
- }
- }
- /**
- * AMD 的 CPU实现
- * @author FX_SKY
- *
- */
- public class AMDCPU implements CPUApi {
- /**
- * CPU的针脚数目
- */
- private int pins = 0;
- /**
- * 构造方法,传人CPU的针脚数目
- * @param pins
- */
- public AMDCPU(int pins) {
- this.pins = pins;
- }
- @Override
- public void calculate() {
- System.out.println("now in AMD CPU,pins="+pins);
- }
- }
3、具体的主板实现
技嘉主板实现的示例代码如下:
- /**
- * 技嘉主板
- * @author FX_SKY
- *
- */
- public class GAMainBoard implements MainBoardApi {
- /**
- * CPU插槽的孔数
- */
- private int cpuHoles = 0;
- /**
- * 构造方法,传人CPU插槽的孔数
- * @param cpuHoles
- */
- public GAMainBoard(int cpuHoles) {
- this.cpuHoles = cpuHoles;
- }
- @Override
- public void installCPU() {
- System.out.println("now in GAMainBoard,cpuHoles="+cpuHoles);
- }
- }
华硕主板实现的示例代码如下:
- /**
- * 华硕主板
- * @author FX_SKY
- *
- */
- public class ASUSMainBoard implements MainBoardApi {
- /**
- * CPU插槽的孔数
- */
- private int cpuHoles = 0;
- /**
- * 构造方法,传人CPU插槽的孔数
- * @param cpuHoles
- */
- public ASUSMainBoard(int cpuHoles) {
- this.cpuHoles = cpuHoles;
- }
- @Override
- public void installCPU() {
- System.out.println("now in ASUSMainBoard,cpuHoles="+cpuHoles);
- }
- }
4、抽象工厂的定义,示例代码如下:
- /**
- * 抽象工厂的接口,声明创建抽象产品对象的操作
- * @author FX_SKY
- *
- */
- public interface AbstractFactory {
- /**
- * 创建CPU的对象
- * @return
- */
- public CPUApi createCPUApi();
- /**
- * 创建主板的对象
- * @return
- */
- public MainBoardApi createMainBoardApi();
- }
5、再看看抽象工厂的实现对象,也就是具体的装机方案对象。
方案1:的实现,示例代码如下:
- /**
- * 装机方案1:AMD CPU + 华硕主板
- * 这里创建CPU和主板对象的时候,是对应的,能匹配上的
- * @author FX_SKY
- *
- */
- public class Schema1 implements AbstractFactory {
- @Override
- public CPUApi createCPUApi() {
- return new AMDCPU(956);
- }
- @Override
- public MainBoardApi createMainBoardApi() {
- return new ASUSMainBoard(956);
- }
- }
方案2:的实现,示例代码如下:
- /**
- * 装机方案2:Intel CPU + 技嘉主板
- * 这里创建CPU和主板对象的时候,是对应的,能匹配上的
- * @author FX_SKY
- *
- */
- public class Schema2 implements AbstractFactory {
- @Override
- public CPUApi createCPUApi() {
- return new IntelCPU(1156);
- }
- @Override
- public MainBoardApi createMainBoardApi() {
- return new GAMainBoard(1156);
- }
- }
6、装机工程师类的实现,示例代码如下:
- /**
- * 装机工程师的类
- * @author FX_SKY
- *
- */
- public class ComputerEngineer {
- /**
- * 定义组装电脑需要的CPU
- */
- private CPUApi cpu;
- /**
- * 定义组装电脑需要的主板
- */
- private MainBoardApi mainBoard;
- public void makeComputer(AbstractFactory schema){
- //1、首先准备好装机所需要的配件
- prepareHardwares(schema);
- //2、组装电脑
- //3、测试电脑
- //4、交付客户
- }
- private void prepareHardwares(AbstractFactory schema) {
- //使用抽象工厂来获取相应的接口对象
- this.cpu = schema.createCPUApi();
- this.mainBoard = schema.createMainBoardApi();
- //测试一下配件是否好用
- this.cpu.calculate();
- this.mainBoard.installCPU();
- }
- }
6、客户端使用抽象工厂,示例代码如下:
- public class Client {
- /**
- * @param args
- */
- public static void main(String[] args) {
- //创建装机工程师对象
- ComputerEngineer cm = new ComputerEngineer();
- //客户选择并创建需要使用的装机方案对象
- Schema1 schema1 = new Schema1();
- //告诉装机工程师自己的装机方案,让装机工程师组装电脑
- cm.makeComputer(schema1);
- }
- }