概念

抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

简介

作用及优势

  • 将一组创建规则类似的产品分为一家工厂创建,易于管理;这类我们称为产品族;

  • 可以减少很多if else,相当于简单工厂的再次抽象;

  • 增加新的具体工厂和产品族很方便,无须修改之前已有的逻辑

  • 当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。

不足之处

  • 产品族扩展非常困难,要增加一个系列的某一产品,不仅要在抽象工厂里面加类型,还要在加具体工厂,然后再加指定产品;所以这种适合非常明确目标的场景下去初始化建设!

场景

  • 一个网站适应所有的浏览器

  • 一个应用程序,适用于所有的操作系统

代码

案例描述

假设有个电脑工厂(抽象工厂),他可以生产屏幕、也可以生产硬盘,但是电脑工厂就是管理产品族的,实际要去实现生产产品的是屏幕工厂,也就是具体工厂去调用实现真正的生产产品逻辑,硬盘工厂也是如此;(脑子懵懵的没关系,根据代码能更好理解)

Suggestion.gif

其实这种模式在平时开发用的不算多,大多数情况下通过简单工厂就能完成,而且这种模式下,会导致子类工厂需要去实现自己没有的功能,这样不算符合接口隔离原则,但是我们可以稍作修改,看下图,我们可以在新增一个中间实现(CommonFactory),他不做任何处理,就替代功能类去实现自己没能力完成的功能,他自己的作用就是减少冗余的无用的代码;

工程目录

抽象工厂模式.jpg

项目类图

抽象工厂.jpg

具体实现

屏幕接口(Monitor ):用于生产屏幕;

/**
 * @author chengxing.wu
 * @date 2021/6/15 17:59
 */
public interface Monitor {
    /**
     * 生产屏幕
     */
    void createMonitor();
}

屏幕具体实现:Ips屏幕和曲面屏;

/**
 * @author chengxing.wu
 * @date 2021/6/15 18:04
 */
public class IpsMonitor implements Monitor {
    @Override
    public void createMonitor() {
        System.out.println("==== 生产ips屏 ====");
    }
}

---------------------------------

/**
 * @author chengxing.wu
 * @date 2021/6/15 18:02
 */
public class QmpMonitor implements Monitor {
    @Override
    public void createMonitor() {
        System.out.println("==== 生产曲面屏 ====");
    }
} 

硬盘抽象类(HardDisk):用于生产硬盘;

/**
 * @author chengxing.wu
 * @date 2021/6/15 18:05
 */
public interface HardDisk {

    /**
     * 生产硬盘
     */
    void createHardDisk();
}

硬盘具体实现:有固态硬盘和机械硬盘

/**
 * @author chengxing.wu
 * @date 2021/6/15 18:07
 */
public class SSDHardDisk implements HardDisk {
    @Override
    public void createHardDisk() {
        System.out.println("==== 生产ssd硬盘 ====");
    }
}

 ---------------------------------

/**
 * @author chengxing.wu@xiaobao100.com
 * @date 2021/6/15 18:06
 */
public class MechanicalHardDisk implements HardDisk {
    @Override
    public void createHardDisk() {
        System.out.println("==== 生产机械硬盘 ====");
    }
}

电脑工厂(抽象工厂ComputerFactory ):

/**
 * @author chengxing.wu
 * @date 2021/6/15 17:50
 */
public abstract class ComputerFactory {
    /**
     * 抽象工厂,电脑工厂既可以生产屏幕,又可以生产硬盘,但是这些都交给对应的厂商去做,自己不做(有子类工厂去做)
     *
     * @param type
     * @return
     */
    public abstract Monitor getMonitor(String type);

    public abstract HardDisk getHardDisk(String type);
}

电脑工厂:这里只负责去获取对应的具体工厂(具有调用具体逻辑实现能力的工厂== 其实就是一个简单工厂);而这个抽象工厂之后会有一个工厂创造器去生产指定类型的工厂;这个之后看测试代码就很清晰!

  • 比如:ProduceFactory 工厂创造器里面传入hdf 就会生成一个硬盘工厂(HardDiskFactory)ComputerFactory;

  • Monitor getMonitor(String type);最后这个返回的对象是由具体对象(HardDiskFactory)生成的;

  • 关系:ProduceFactory → ComputerFactory(tips);→ SSDHardDisk

tips: ComputerFactory的类型是(HardDiskFactory),其实就是(HardDiskFactory instanceof ComputerFactory )= true

公共继承类(CommonFactory),去除冗余代码;

/**
 * 项目: question-study-improve
 * <p>
 * 功能描述: 公共工厂
 *
 * @author: WuChengXing
 * @create: 2021-07-09 19:01
 **/
public class CommonFactory extends ComputerFactory{
    @Override
    public Monitor getMonitor(String type) {
        return null;
    }

    @Override
    public HardDisk getHardDisk(String type) {
        return null;
    }
}

硬盘生产工厂(HardDiskFactory )

 /**
 * @author chengxing.wu
 * @date 2021/6/15 18:10
 */
public class HardDiskFactory extends CommonFactory {

    /**
     * 这里不关心屏幕的生产
     *
     * @param type
     * @return
     */
    @Override
    public HardDisk getHardDisk(String type) {
        if ("m".equals(type)) {
            System.out.println("xxxxxxxx 准备生产机械硬盘 xxxxxxxx");
            return new MechanicalHardDisk();
        } else if ("s".equals(type)) {
            System.out.println("xxxxxxxx 准备生产机SSD硬盘 xxxxxxxx");
            return new SSDHardDisk();
        }
        return null;
    }
}

硬盘生产工厂,这里就是个简单工厂,根据传入的类型,去生产指定的产品;但是这里生产的产品,在抽象工厂里,是一系列类似的东西;而这个工厂也是一个具体工厂;

  • HardDiskFactory 是一个具体工厂,其实就是一个简单工厂的实现

  • ComputerFactory.getHardDisk(String type); → HardDiskFactory → SSDHardDisk;这整个链路连在一起就叫产品族;所以说新增一个产品会很麻烦,需要加一条链路;

屏幕生产工厂:跟硬盘的差不多:

/**
 * @author chengxing.wu
 * @date 2021/6/15 17:58
 */
public class MonitorFactory extends CommonFactory {

    @Override
    public Monitor getMonitor(String type) {
        if ("q".equals(type)) {
            System.out.println("xxxxxxxx 准备生产曲面屏 xxxxxxxx");
            return new QmpMonitor();
        } else if ("i".equals(type)) {
            System.out.println("xxxxxxxx 准备生产IPS屏 xxxxxxxx");
            return new IpsMonitor();
        }
        return null;
    }
}

工厂创造器:这通过传入指定工厂的类型,去获取对应工厂;

/**
 * @author chengxing.wu
 * @date 2021/6/15 18:16
 */
public class ProduceFactory {

    public static ComputerFactory create(String type) {
        if ("mf".equals(type)) {
            System.out.println("-------- 联系屏幕工厂 --------");
            return new MonitorFactory();
        } else if ("hdf".equals(type)) {
            System.out.println("-------- 联系硬盘工厂 --------");
            return new HardDiskFactory();
        }
        return null;
    }
}

测试

/**
 * @author chengxing.wu@xiaobao100.com
 * @date 2021/6/15 18:19
 */
public class AbstractFactoryTest {
    public static void main(String[] args) {
        // 获取到 屏幕的生产工厂
        ComputerFactory monitorFactory = ProduceFactory.create("mf");
        // 获取到 曲面屏
        Monitor qmp = monitorFactory.getMonitor("q");
        //开始生产
        qmp.createMonitor();
        Monitor ips = monitorFactory.getMonitor("i");
        ips.createMonitor();

        ComputerFactory hardDiskFactory = ProduceFactory.create("hdf");
        HardDisk mechanicalHardDisk = hardDiskFactory.getHardDisk("m");
        mechanicalHardDisk.createHardDisk();
        HardDisk ssdHardDisk = hardDiskFactory.getHardDisk("s");
        ssdHardDisk.createHardDisk();
    }
}

结果:

-------- 联系屏幕工厂 --------
xxxxxxxx 准备生产曲面屏 xxxxxxxx
==== 生产曲面屏 ====
xxxxxxxx 准备生产IPS屏 xxxxxxxx
==== 生产ips屏 ====
-------- 联系硬盘工厂 --------
xxxxxxxx 准备生产机械硬盘 xxxxxxxx
==== 生产机械硬盘 ====
xxxxxxxx 准备生产机SSD硬盘 xxxxxxxx
==== 生产ssd硬盘 ====