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

设计模式的分类

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

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

设计模式系列文章传送门

设计模式的 7 大原则

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

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

什么是抽象工厂模式?

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

产品族

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

抽象工厂五要素

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

案例分享

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

小汽车接口(抽象产品)

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

java 复制代码
public interface CompactCar {

    //汽车品牌
    String getBrand();

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

    //汽车型号
    String getModel();

    //汽车颜色
    String getColor();

}

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

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

java 复制代码
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 "蓝色";
    }
}

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

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

java 复制代码
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 "炫酷黑";
    }
}

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

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

java 复制代码
public interface BigTruck {

    //汽车品牌
    String getBrand();

    //汽车载重
    String getLoad();

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

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

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

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

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

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

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

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

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

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

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

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

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

java 复制代码
public interface AbstractCarFactory {

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

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

}

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

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

java 复制代码
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;
    }
}

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

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

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

java 复制代码
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;
    }
}

定义工厂创造器

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

java 复制代码
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;
    }
}

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

测试验证

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

java 复制代码
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());

    }

}

测试执行结果如下:

powershell 复制代码
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

工厂模式优缺点

优点:

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

缺点:

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

应用场景

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

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

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

相关推荐
Ray Liang17 分钟前
用六边形架构与整洁架构对比是伪命题?
java·python·c#·架构设计
Sailing20 分钟前
🚀 别再乱写 16px 了!CSS 单位体系已经进入“计算时代”,真正的响应式布局
前端·css·面试
Java水解33 分钟前
Java 中间件:Dubbo 服务降级(Mock 机制)
java·后端
SuperEugene3 小时前
Vue状态管理扫盲篇:Vuex 到 Pinia | 为什么大家都在迁移?核心用法对比
前端·vue.js·面试
Hilaku3 小时前
我会如何考核一个在简历里大谈 AI 提效的高级前端?
前端·javascript·面试
七月丶4 小时前
别再手动凑 PR 了:这个 AI Skill 会按仓库习惯自动建分支、拆提交、提 PR
人工智能·设计模式·程序员
刀法如飞4 小时前
从程序员到架构师:6大编程范式全解析与实践对比
设计模式·系统架构·编程范式
前端Hardy4 小时前
别再用 $emit 满天飞了!Vue 3 组件通信的 4 种正确姿势,第 3 种 90% 的人不知道
前端·vue.js·面试
我叫黑大帅4 小时前
前端如何利用 GitHub Actions 自动构建并发布到 GitHub Pages?
前端·面试·github
我叫黑大帅4 小时前
前端总说的防抖与节流到底是什么?
前端·javascript·面试