《Java Design Patterns》第三章 抽象工厂模式

第三章 抽象工厂模式

在工厂方法模式中,通过引入工厂等级结构,解决了 简单工厂模式 中工厂类过于庞大,职责过重的问题。但是由于工厂方法模式中的每一个工厂只生产一类产品,导致系统中存在大量工厂类,增加系统开销。

因此我们需要将一些相关的产品组成一个“产品族”,由同一个工厂生产。

一、抽象工厂模式

1.1 设计一款界面皮肤库

设计一款界面皮肤库,可以通过菜单来选择皮肤,不同的皮肤将提供视觉效果不同的按钮、文本框、组合框等。

按照之前的 工厂方法模式 设计,如下:

工厂方法模式.jpg

当我们需要增加 Winter风格 的按钮时,只需要继承抽象工厂并生产出对应的按钮即可。该系统具备良好的灵活性和可扩展性,开发可以在不修改现有代码的基础上增加新的皮肤。

1.2 缺陷与问题

该设计模式提供了大量的工厂来创建具体的界面组件,可以灵活的配置风格,但是存在以下问题:

  1. 新增产品时,需要同时新增一个具体工厂类,类的个数成对增加,会增大系统的开销
  2. 由于某一种风格的按钮、文本框、组合框通常都是一起使用的,但是因为其工厂方法分离,可能会导致使用时的选择失误

1.3 解决方案

将一组产品类定义为一个“产品族”(如按钮、文本框、组合框统称为一个产品族),将之前一个产品对应一个具体工厂的模式改为-一个产品族对应一个产品工厂(如Spring风格工厂,能够生产Spring风格按钮、Spring风格文本框、Spring风格组合框)。

1.4 产品等级结构与产品族

  1. 产品等级结构
    1. 1.3 解决方案 中,抽象工厂与Spring风格工厂、Summer风格工厂之间的关系构成了一个产品等级结构
    2. 抽象工厂类是父类,具体工厂类是子类
    3. 产品等级扩展,只需要继续实现子类即可(如新增Winter风格工厂,用于生产Winter风格的按钮、文本框、组合框)
  2. 产品族:
    1. 即各个具体工厂生产的产品统称(如Spring风格工厂,能够生产Spring风格按钮、Spring风格文本框、Spring风格组合框)

当系统所提供的工厂生产的具体产品并不是一个简单的对象,而是位于多个不同产品等级结构、属于不同类型的具体产品时就可以使用抽象工厂模式。

二、抽象工厂模式

2.1 概述

抽象工厂模式:提供一个创建一系列相关或互相依赖对象的接口,而无须指定它们具体的类。

抽象工厂模式又称为 Kit模式,属于对象创建型模式。

在抽象工厂模式中,每一个具体工厂都提供多个工厂方法,用于生产多种不同类型的产品。这些产品构成了一个产品族。

抽象工厂模式

从图中可以看出,如果需要新增其他风格的按钮、文本框,只需要新增一个具体工厂,由该工厂的多个工厂方法产出具体的产品。

同时,缺点也很明显,如果我们想新增图片类型产品,必须同时修改抽象工厂及其所有的具体工厂。

2.2 抽象工厂模式中的几个角色

  1. AbstractFactory - 抽象工厂
    1. 声明了一组用于创建一族产品的方法,每一个方法对应一种产品
  2. ConcreteFactory - 具体工厂
    1. 实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成一个产品族
  3. AbstractProduct - 抽象产品
    1. 每种产品的抽象对象
  4. ConcreteProduct 具体产品
    1. 由具体工厂生产的具体产品对象

2.3 具体实践

/**
 * 手机游戏软件
 * 针对 Symbian、Android、WindowsPhone 等多个智能手机平台,
 * 提供不同的游戏操作控制和游戏界面控制
 */
public class Gaming {
    // 抽象产品类
    interface Operation{}
    // 具体产品类
    class SymbianOperation implements Operation{}
    class AndroidOperation implements Operation{}
    class WindowsPhoneOperation implements Operation{}

    interface HML{}
    class SymbianHML implements HML{}
    class AndroidHML implements HML{}
    class WindowsPhoneHML implements HML{}

    // 抽象工厂类
    interface Factory{
        Operation getOperation();
        HML getHML();
    }
    // 具体工厂类
    class SymbianFactory implements Factory{
        @Override
        public Operation getOperation() {
            return new SymbianOperation();
        }
        @Override
        public HML getHML() {
            return new SymbianHML();
        }
    }
    class AndroidFactory implements Factory{
        @Override
        public Operation getOperation() {
            return new AndroidOperation();
        }
        @Override
        public HML getHML() {
            return new AndroidHML();
        }
    }
    class WindowsPhoneFactory implements Factory{
        @Override
        public Operation getOperation() {
            return new WindowsPhoneOperation();
        }
        @Override
        public HML getHML() {
            return new WindowsPhoneHML();
        }
    }
}

三、“开闭原则”的倾斜性

在抽象工厂模式中,增加新的产品族很方便(如增加Winter类型的界面),但是增加新的产品等级结构很麻烦(如增加单选框类型的产品,需要修改抽象工厂及其所有的具体工厂),这种性质被称为“开闭原则”的倾斜性。

“开闭原则”要求系统对扩展开发,对修改封闭,通过扩展达到增强其功能的目的,对于设计多个产品族与多个产品等级结构的系统,其功能增强包括两方面:

  1. 增加产品族,很好地支持了“开闭原则”,只需新增具体产品和新增一个具体工厂即可
  2. 增加产品等级结构:违背了“开闭原则”,因为需要修改所有的抽象工厂与具体工厂才能实现扩展

四、总结

优点

  1. 抽象工厂模式隔离了具体类的生成,使客户不需要知道何时被创建
  2. 当一个产品族中的多个对象被设计为一起工作时,它能够保证客户端始终只使用一个产品族对象
  3. 增加新的产品族很方便,无须修改已有系统,符合“开闭原则”

缺点

  1. 增加新的产品等级结构时,违背了“开闭原则”

适用场景

  1. 系统不依赖于产品类的具体创建、组合及表达的细节
  2. 系统中有多于一个的产品族,且每次只使用其中某一个产品族
  3. 同一个产品族的产品配合使用
  4. 产品等级结构稳定,设计完成后,不再修改系统中新的产品等级结构
文章作者: koral
文章链接: http://luokaiii.github.io/2019/06/26/读书笔记/《JavaDesignPatterns》/5.抽象工厂模式/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自