抽象工厂模式

224 阅读4分钟

简述

上篇工厂方法模式有一个严重的缺点,每个工厂类只能创建一个具体的产品,可能会导致系统中存在大量的工厂类,势必增加系统的维护成本。这里我们如果可以将产品划分为产品族的概念,就可以使用抽象工厂方法来创建一个产品族中的所有产品,而无需关注其中的构建过程。

UML类图

抽象工厂模式.png

ProductA: 抽象出来的一个产品A,可以是接口,也可以是抽象类。 ConcreteProductA1: A类产品中的A1的具体实现 ConcreteProductA2: A类产品中的A2的具体实现。 此处A1和A2可以理解为同一类产品,但是属于两个不同产品族。 ProductB: 抽象出来的一个产品B,可以是接口,也可以是抽象类。 ConcreteProductB1: B类产品中的B1的具体实现 ConcreteProductB2: B类产品中的B2的具体实现。 此处B1和B2可以理解为同一类产品,但是属于两个不同产品族。 Factory:抽象工厂类,定义了创建一个产品族中所有产品的方法 ConcreteFactory1:1类产品族工厂,专门创建1类产品,如A1,B1. ConcreteFactory2:2类产品族工厂,专门创建1类产品,如A2,B2.

要点

  1. 工厂方法模式是创建一个产品。 抽象工厂模式是创建一系列产品。
  2. 每个产品都由不同的产品族实现.

案例

还是拿汽车工厂来说,之前是直接创建car。 现在我们的工厂负责生产汽车的各个零部件。比如生产汽车的引擎,方向盘,轮胎等等。

/**********************抽象工厂**********************************/

    interface  IEngine {
        //每个引擎都有运行的方法
        void run();
    }

    class BMEngine implements IEngine {
        public void run() {
            System.out.println("宝马汽车引擎在运行");
        }
    }

    class BZEngine implements IEngine {
        public void run() {
            System.out.println("奔驰汽车引擎在运行");
        }
    }

    interface IPanel {
        //每个仪表盘都有运行的方法
        void run();
    }

    class BMPanel implements IPanel {
        public void run() {
            System.out.println("宝马汽车仪表盘在运行");
        }
    }

    class BZPanel implements IPanel {
        public void run() {
            System.out.println("奔驰汽车仪表盘在运行");
        }
    }

    // 定义抽象工厂,专门负责生产汽车引擎和仪表盘
    interface IAbstractFactory {
        IEngine createEngine();
        IPanel createPanel();
    }

    class BMProductFactory implements IAbstractFactory {
        public IEngine createEngine() {
            System.out.println("生产了宝马牌引擎");
            return new BMEngine();
        }

        public IPanel createPanel() {
            System.out.println("生产了宝马牌仪表盘");
            return new BMPanel();
        }
    }

    class BZProductFactory implements IAbstractFactory {
        public IEngine createEngine() {
            System.out.println("生产了奔驰牌引擎");
            return new BZEngine();
        }

        public IPanel createPanel() {
            System.out.println("生产了奔驰牌仪表盘");
            return new BZPanel();
        }
    }

main 函数中的代码如下:

 //抽象工厂模式
IAbstractFactory absBMFactory = new BMProductFactory();
absBMFactory.createEngine().run();
absBMFactory.createPanel().run();

IAbstractFactory absBZFactory = new BZProductFactory();
absBZFactory.createEngine().run();
absBZFactory.createPanel().run();

最后运行结果

2020-03-18 02:58:00.879 5455-5455/? I/System.out: 生产了宝马牌引擎
2020-03-18 02:58:00.879 5455-5455/? I/System.out: 宝马汽车引擎在运行
2020-03-18 02:58:00.879 5455-5455/? I/System.out: 生产了宝马牌仪表盘
2020-03-18 02:58:00.879 5455-5455/? I/System.out: 宝马汽车仪表盘在运行
2020-03-18 02:58:00.879 5455-5455/? I/System.out: 生产了奔驰牌引擎
2020-03-18 02:58:00.879 5455-5455/? I/System.out: 奔驰汽车引擎在运行
2020-03-18 02:58:00.879 5455-5455/? I/System.out: 生产了奔驰牌仪表盘
2020-03-18 02:58:00.879 5455-5455/? I/System.out: 奔驰汽车仪表盘在运行

总结

优点:

  1. 抽象工厂隔离了具体类的生成,使得客户并不需要知道是怎么创建的。这就带来了扩展性
  2. 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象
  3. 增加新的产品族非常方便,无需修改已有系统,符合开闭原则

缺点: 抽象工厂最大的缺点就是不能扩展产品族中的产品。比如上面的案例中,我想再添加生成方向盘的功能,那之前所有的工厂类都需要修改才能满足要求。这明显带来了很大的不便,也违背了开闭原则

适用场景

  1. 多个产品需要同时被创建。
  2. 产品结构稳定。 正如优缺点中说的,抽象工厂模式极不方便扩展具体的产品。
  3. 这些被创建的产品又能归属与某一大类中去。比如我们生产的引擎,仪表盘,方向盘,都可以归类到汽车零部件。 满足上面3点就可以使用抽象工厂了。并且扩展工厂也是及其方便的。