设计模式--抽象工厂模式【创建型模式】

设计模式的分类

我们都知道有 23 种设计模式,这 23 种设计模式可分为如下三类:

  • 创建型模式(5 种):单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。
  • 结构型模式(7 种):适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
  • 行为型模式(11 种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

在这里插入图片描述

设计模式系列文章传送门

设计模式的 7 大原则

设计模式–单例模式【创建型模式】

设计模式–工厂方法模式【创建型模式】

什么是抽象工厂模式

抽象工厂模式是一种创建型模式,该模式提供了一个超级工厂(抽象工厂),其他工厂来是实现这个工厂接口,同时还有一个工厂创建类,通过传入不同的参数,来创建不同的工厂,抽象工厂 模式是对工厂模式的扩展,工厂模式只是某类产品的工厂,而抽象工厂则是多类产品的工厂,可以理解为一类产品(产品族)的工厂,而抽象工厂就是工厂的工厂,是一个超级工厂。

产品族

产品族是指一类具有共同特征、相互关联的产品组合,它指的是一系列的产品,这些产品可能具有不同的规格、配置或者功能,抽象工厂模式就是对一系列产品就组成一个产品族,(工厂方法提供的一系列产品组成一个产品)。比如同样是车,我们会区分家用小汽车和货运重卡,而家用小汽车又有小米、小鹏等品牌,而活用重卡又有解放、东风等品牌,而他们又都属于车这个产品族。

抽象工厂五要素

  • 抽象工厂:定义一个接口,它声明了一组创建相关产品对象的方法,这些方法的返回值都是一个抽象产品。
  • 具体工厂:实现了抽象工厂中创建对象的方法,创建出具体的产品对象。
  • 抽象产品:定义了一个接口,声明了产品的一些方法。
  • 具体产品:定义了抽象产品下的某个具体产品,实现了抽象产品接口中的方法。
  • 工厂创造器:定义了一个静态方法,根据传入的参数类型,创建一个具体的工厂类。

案例分享

我们使用车产品模拟一个产品大类(产品族),车产品中又有家用小汽车和货用重卡,而家用小汽车又有小米、小鹏等品牌,而活用重卡又有解放、东风等品牌,我们使用这个案例来演示抽象工厂模式

小汽车接口(抽象产品)

定义小汽车接口,包含汽车创始人、型号、品牌、颜色等方法,代码如下:

public interface CompactCar {

    //汽车品牌
    String getBrand();

    //汽车创始人
    String getFounder();

    //汽车型号
    String getModel();

    //汽车颜色
    String getColor();

}

定义小米汽车(具体产品)

家用小汽车有诸多品牌,我们定义一个小米汽车,代码如下:

public class XiaoMiCar implements CompactCar {
    @Override
    public String getBrand() {
        return "小米";
    }

    @Override
    public String getFounder() {
        return "雷布斯";
    }

    @Override
    public String getModel() {
        return "su7";
    }

    @Override
    public String getColor() {
        return "蓝色";
    }
}

定义小鹏汽车(具体产品)

我们再定义一个家用汽车品牌中的小鹏汽车,代码如下:

public class XiaoPengCar implements CompactCar {
    @Override
    public String getBrand() {
        return "小鹏";
    }

    @Override
    public String getFounder() {
        return "何小鹏";
    }

    @Override
    public String getModel() {
        return "小鹏P7";
    }

    @Override
    public String getColor() {
        return "炫酷黑";
    }
}

货用重卡接口(抽象产品)

货用重卡也是车中的一类,货用重卡接口包含汽车品牌、载重、颜色等方法,代码如下:

public interface BigTruck {

    //汽车品牌
    String getBrand();

    //汽车载重
    String getLoad();

    //汽车颜色
    String getColor();
    
}

定义东风重卡汽车(具体产品)

货用重卡汽车有诸多品牌,我们定义一个东风重卡汽车,代码如下:

public class DongFengCar implements BigTruck{
    @Override
    public String getBrand() {
        return "东风重卡";
    }

    @Override
    public String getLoad() {
        return "60吨";
    }

    @Override
    public String getColor() {
        return "红色";
    }
}

定义解放重卡汽车(具体产品)

解放重卡汽车有诸多品牌,我们定义一个解放重卡汽车,代码如下:

public class JieFangCar implements BigTruck{
    @Override
    public String getBrand() {
        return "一汽解放重卡";
    }

    @Override
    public String getLoad() {
        return "50吨";
    }

    @Override
    public String getColor() {
        return "橙色";
    }
}

定义抽象车工厂接口(抽象工厂)

抽象车工厂接口中声明了两个方法,分别是创建家用小汽车和货用重卡。

public interface AbstractCarFactory {

    //生产小汽车接口
    CompactCar createCompactCar(String carType);

    //生产大货车接口
    BigTruck createBigTruck(String carType);

}

定义小汽车工厂接口(具体工厂)

小汽车工厂实现了抽象车工厂接口,代码如下:

public class CompactCarFactory implements AbstractCarFactory {

    //创建小米汽车
    @Override
    public CompactCar createCompactCar(String carType) {
        if("xiaomi".equals(carType)){
            return new XiaoMiCar();
        }else  if("xiaopeng".equals(carType)){
            return new XiaoPengCar();
        }
        return null;
    }

    @Override
    public BigTruck createBigTruck(String carType) {
        return null;
    }
}

可以看到小汽车工厂也实现了货用重卡的方法,这就是抽象工厂方法的弊端,小汽车工厂根本用不到货用重卡的方法,但因为实现了抽象车工厂接口,就必须重写货用重卡的方法。

定义货用重卡工厂接口(具体工厂)

货用重卡工厂实现了抽象车工厂接口,代码如下:

public class BigTruckFactory implements AbstractCarFactory{
    @Override
    public CompactCar createCompactCar(String carType) {
        return null;
    }

    @Override
    public BigTruck createBigTruck(String carType) {
        if("dongfeng".equals(carType)){
            return new DongFengCar();
        }else if("jiefang".equals(carType)){
            return new JieFangCar();
        }
        return null;
    }
}

定义工厂创造器

定义工厂创造器可以根据我们传入的工厂类型帮我们生产具体的工厂,代码如下:

public class FactoryCreator {

    public static AbstractCarFactory createFactory(String factoryType) {
        if ("compact".equals(factoryType)) {
            return new CompactCarFactory();
        } else if ("bigtruck".equals(factoryType)) {
            return new BigTruckFactory();
        }
        return null;
    }
}

看起来工厂创造器其实是可有可无的,非必须得,看个人喜好。

测试验证

测试抽象工厂模式代码如下:

public class CarClient {

    public static void main(String[] args) {
        AbstractCarFactory compact = FactoryCreator.createFactory("compact");
        CompactCar xiaomi = compact.createCompactCar("xiaomi");
        System.out.println(xiaomi.toString());
        CompactCar xiaopeng = compact.createCompactCar("xiaopeng");
        System.out.println(xiaopeng.toString());
        AbstractCarFactory bigtruck = FactoryCreator.createFactory("bigtruck");
        BigTruck dongfeng = bigtruck.createBigTruck("dongfeng");
        System.out.println(dongfeng.toString());
        BigTruck jiefang = bigtruck.createBigTruck("jiefang");
        System.out.println(jiefang.toString());

    }

}

测试执行结果如下:

com.xxx.xxx.xxx.factory.abstractfactory.XiaoMiCar@6d5380c2
com.xxx.xxx.xxx.factory.abstractfactory.XiaoPengCar@45ff54e6
com.xxx.xxx.xxx.factory.abstractfactory.DongFengCar@2328c243
com.xxx.xxx.xxx.factory.abstractfactory.JieFangCar@bebdb06

工厂模式优缺点

优点:

  • 客户端独立于具体的实现类,将产品的使用和创建分开,客户端使用工厂来穿件产品,无需关心产品的实现,隐藏了产品细节同时也有一定的解耦。
  • 增加产品容易,比如我们现在有小米和小鹏家用汽车,再增加一个蔚来汽车是很容易的。

缺点:

  • 增加新品类困难,如果想要新增一个新的品类,需要修改抽象接口代码已经下游所有代码,比如我们新增一个火车类(这里区别于新在一个品类的一个产品)。
  • 引入了抽象层,增加了系统的抽象性和理解难度,增加了代码复杂度,对于不熟悉该模式的开发人员来说,理解起来可能会有一些困难。

应用场景

  • 需要对一个产品族下的不同产品类型提供同意的访问接口,不关心某个产品的具体实现的场景。
  • 需要运行中动态的选择某种产品的场景。

总结:本篇结合理论和案例分享了抽象工厂设计模式,相比工厂方法模式,抽象工厂方法模式理解起来会更困难一点,希望不熟悉抽象工厂模式的朋友们可以静下心来分析,相信会有所帮助。

如有不正确的地方欢迎各位指出纠正。


http://www.niftyadmin.cn/n/5797846.html

相关文章

单片机:实现驱动超声波(附带源码)

单片机实现驱动超声波模块 超声波模块(如HC-SR04)广泛应用于距离测量、避障系统、自动驾驶等嵌入式项目中。它能够通过发射超声波信号并接收反射波来计算物体的距离。本文将介绍如何使用单片机(如51系列单片机)驱动超声波模块&am…

面试小札:Java后端闪电五连鞭_8

1. Kafka消息模型及其组成部分 - 消息(Message):是Kafka中最基本的数据单元。消息包含一个键(key)、一个值(value)和一个时间戳(timestamp)。键可以用于对消息进行分区等…

React State(状态)

React State(状态) 引言 在React的世界里,状态(State)是一个核心概念,它允许我们创建动态和交互式的用户界面。状态是React组件内部数据的存储机制,当状态发生变化时,React会自动重新渲染组件&#xff0c…

20241220流水的日报 mysql的between可以用于字符串 sql 所有老日期的,保留最新日期

1.F310A RKP有效性验证讨论:需连外网,需先用app生成标志,工具读标志。 2.M200 适配一个 给客户写配置的工具 mysql的between可以用于字符串 批量打印包装箱时,提示有重复N条的处理方法: --先备份数据库,删…

Actor模型和Reactor模型,Rust下的actix-web基于Actix Actor框架

Actor模型与Reactor模型详解 Actor模型 Actor模型是一种用于并发计算的理论模型,由卡尔休伊特(Carl Hewitt)在1973年提出。它将系统中的并发实体抽象为“演员”(Actor),每个演员都是独立的计算单元&#…

LeetCode429周赛T4

最小化二进制字符串中最长相同子字符串的长度 在处理二进制字符串问题时,优化字符串结构以满足特定条件是一项常见的挑战。本文将探讨一个具体的问题:给定一个长度为 n 的二进制字符串 s 和一个整数 numOps,通过最多 numOps 次位翻转操作&am…

三分钟完成vue项目中iconfont图标的导入

iconfont 提供了丰富的图标库,也允许个人上传分享图标,非常复合中文视觉体验。平时的开发中也离不开iconfont图标的使用,今天就给大家聊一下iconfont图表在vue项目中的快速导入! 1、添加图标 登录iconfont-阿里巴巴矢量图标库&a…

细说STM32F407单片机DMA方式读写SPI FLASH W25Q16BV

目录 一、 工程配置 1、时钟、DEBUG、GPIO、USART6、Code Generator 2、SPI2 3、NVIC 二、软件设计 1、 FALSH、KEY_LED 2、 spi.h 3、 spi.c 4、main.c 三、下载、运行 SPI接口具有发送和接收两个DMA请求,在大数据量传输时,使用DMA效率更高&a…