「聊设计模式」之抽象工厂模式(Abstract Factory)

news2024/11/26 4:28:06

🏆本文收录于《聊设计模式》专栏,专门攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎持续关注&&收藏&&订阅!


前言

  在软件开发中,设计模式是一种被广泛使用的经验总结,它们为我们提供了一套已经经过验证的,可以复用的解决方案,可以帮助开发人员有效地解决常见问题,提高软件质量和可维护性。

  本文将介绍抽象工厂模式(Abstract Factory),这是一种创建型设计模式,它提供了一种创建与一组相关对象的方式,而无需指定其具体类。本文将详细介绍抽象工厂模式的概念、实现方法以及测试用例,并展示它在Java中的实现。

摘要

  抽象工厂模式是一种通过接口或抽象类来创建一系列相关或依赖对象的设计模式。它是工厂方法模式的扩展,它可以创建多个产品族,而工厂方法模式只能创建单个产品族。抽象工厂模式通过将工厂的抽象与产品的抽象相匹配来实现这一目标。

抽象工厂模式

概念

  抽象工厂模式是一种创建型设计模式,它提供了创建一组相关或依赖对象的接口,无需指定它们具体的类。它通过将工厂的抽象与产品的抽象相匹配来实现这一目标。

  抽象工厂模式是在工厂方法模式的基础上发展而来的。工厂方法模式只能创建单个产品族,而抽象工厂模式可以创建多个产品族。在抽象工厂模式中,每个工厂类只负责创建对应产品族的产品,在工厂内部,通过抽象产品的公共接口来实现不同产品族的产品创建。

实现方法

如下我给大家用代码亲自演示一下抽象工厂模式,具体请看如下代码:

1. 创建抽象工厂类

  抽象工厂类中需要定义用于创建产品族的抽象方法,抽象方法返回抽象产品。在Java中,可以使用抽象类或接口来定义抽象工厂。

package com.example.javaDesignPattern.abstractFactory;

/**
 * 抽象工厂类
 *
 * @author bug菌
 * @version 1.0
 * @date 2023/9/18 17:29
 */
public abstract class AbstractFactory {
    public abstract ProductA createProductA();
    public abstract ProductB createProductB();
}

2. 创建具体工厂类

  具体工厂类实现抽象工厂类中定义的抽象方法,用于创建具体的产品。具体工厂类中也可以包含额外的方法和属性,用于定制化产品的创建。

如下创建第一个具体工厂类,示例代码如下:

package com.example.javaDesignPattern.abstractFactory;

/**
 * 创建具体工厂类
 *
 * @author bug菌
 * @version 1.0
 * @date 2023/9/18 17:30
 */
public class ConcreteFactory1 extends AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ConcreteProductA1();
    }
    @Override
    public ProductB createProductB() {
        return new ConcreteProductB1();
    }
}

如下接着创建第二个具体工厂类,示例代码如下:

package com.example.javaDesignPattern.abstractFactory;

/**
 * 创建具体工厂类
 *
 * @author bug菌
 * @version 1.0
 * @date 2023/9/18 17:30
 */
public class ConcreteFactory2 extends AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ConcreteProductA2();
    }
    @Override
    public ProductB createProductB() {
        return new ConcreteProductB2();
    }
}

3. 创建抽象产品类

  抽象产品类定义产品的公共接口,从而使不同具体产品类可以实现相同的接口。

public abstract class ProductA {
    public abstract void display();
}
public abstract class ProductB {
    public abstract void show();
}

  以上代码是创建抽象类的示例。抽象类是不能被实例化的类,只能被继承,因此抽象类通常用于作为其他类的基类。在以上代码中,ProductA和ProductB都是抽象类。

  在ProductA类中,定义了一个抽象方法display(),该方法没有具体的实现,只有方法签名。所有继承自ProductA的子类在实现该方法时,需要给出具体的实现。由于抽象类不能被实例化,因此使用抽象方法可以让子类在具体实现时覆盖基类的实现,实现多态性。

  在ProductB类中,同样定义了一个抽象方法show()。和ProductA类中的display()方法类似,子类需要实现show()方法以满足多态性的需求。

  需要注意的是,抽象类中可以包含非抽象方法和属性,在子类继承后可以直接使用,不需要覆盖实现。

4. 创建具体产品类

  具体产品类实现抽象产品类中定义的抽象方法,用于实例化具体的产品。

public class ConcreteProductA1 extends ProductA {
    @Override
    public void display() {
        System.out.println("ConcreteProductA1 display");
    }
}
public class ConcreteProductB1 extends ProductB {
    @Override
    public void show() {
        System.out.println("ConcreteProductB1 show");
    }
}
public class ConcreteProductA2 extends ProductA {
    @Override
    public void display() {
        System.out.println("ConcreteProductA2 display");
    }
}

public class ConcreteProductB2 extends ProductB {
    @Override
    public void show() {
        System.out.println("ConcreteProductB2 show");
    }
}

  在如上代码,ConcreteProductA1ConcreteProductA2继承了抽象产品类ProductA,分别实现了抽象产品类中的display()方法;ConcreteProductB1ConcreteProductB2继承了抽象产品类ProductB,分别实现了抽象产品类中的show()方法。这些具体产品类将被工厂类使用来创建具体产品对象。

5. 创建客户端代码

  客户端代码使用抽象工厂来获取其需要使用的产品,客户端代码不需要知道如何创建产品,只需要知道如何使用它们。

package com.example.javaDesignPattern.abstractFactory;

/**
 * 创建客户端
 *
 * @author bug菌
 * @version 1.0
 * @date 2023/9/18 17:33
 */
public class Client {
    public static void main(String[] args) {
        AbstractFactory factory1 = new ConcreteFactory1();
        AbstractFactory factory2 = new ConcreteFactory2();

        ProductA productA1 = factory1.createProductA();
        ProductB productB1 = factory1.createProductB();
        productA1.display();
        productB1.show();

        ProductA productA2 = factory2.createProductA();
        ProductB productB2 = factory2.createProductB();
        productA2.display();
        productB2.show();
    }
}

  客户端展示了抽象工厂模式的使用。客户端通过创建具体工厂对象(ConcreteFactory1ConcreteFactory2)来获得不同种类的产品对象(ProductAProductB)。客户端并不直接使用产品对象,而是通过工厂对象创建产品对象并调用它们的方法(display()show())。这样可以封装产品对象的创建过程,使得客户端只需要关注工厂对象和产品对象的接口,而不需要了解具体实现细节。

启动客户端测试结果如下:

在这里插入图片描述

【代码方法解读】

  其中,抽象工厂 AbstractFactory 定义了两个抽象方法 createProductA() createProductB(),分别用于创建产品 A 和产品 B。具体的工厂类ConcreteFactory1ConcreteFactory2 分别实现了这两个方法,并且分别用于创建不同的产品。

  在 Client 类的 main() 方法中,首先分别创建了 ConcreteFactory1ConcreteFactory2 两个工厂的实例。接着,通过这两个工厂实例的 createProductA()createProductB() 方法创建了不同的产品对象,并分别调用了它们的 display()show() 方法。

  因此,抽象工厂模式的主要优点是能够提供一致的产品族创建接口,使得客户端可以方便地创建一组相关的产品。同时也能遵循开闭原则,使得增加新的产品族比较容易,但同时也增加了类的数量,降低了系统的灵活性和可扩展性。

附录源码

  如上涉及代码均已上传同步在GitHub,提供给同学们参考性学习。

总结

  本文着重介绍了抽象工厂模式,该模式是创建型设计模式的一种,它提供了一种创建一组相关或依赖对象的方式,无需指定其具体类。抽象工厂模式是工厂方法模式的扩展,可以创建多个产品族,而工厂方法模式只能创建单个产品族。

  为了实现抽象工厂模式,需要先创建抽象工厂类,其中定义用于创建产品族的抽象方法,抽象方法返回抽象产品。具体工厂类实现抽象工厂类中定义的抽象方法,用于创建具体的产品。抽象产品类定义产品的公共接口,具体产品类实现抽象产品类中定义的抽象方法,用于实例化具体的产品。

  在客户端代码中,使用抽象工厂来获取需要使用的产品,不需要知道如何创建产品,只需要知道如何使用它们。

  抽象工厂模式可以帮助开发人员有效地解决常见问题,提高软件质量和可维护性,是软件开发中经常使用的一种设计模式。

☀️建议/推荐你


  如果想系统性的全面学习设计模式,建议小伙伴们直接毫无顾忌的关注这个专栏《聊设计模式》,无论你是想提升自己的编程技术,还是渴望更好地理解代码背后的设计思想,本专栏都会为你提供实用的知识和启发,帮助你更好地解决日常开发中的挑战,将代码变得更加优雅、灵活和可维护!

📣关于我


我是bug菌,CSDN | 掘金 | infoQ | 51CTO 等社区博客专家,历届博客之星Top30,掘金年度人气作者Top40,51CTO年度博主Top12,华为云 | 阿里云| 腾讯云等社区优质创作者,全网粉丝合计15w+ ;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板等海量资料。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1020209.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

kudu 1.4.0 离线安装

1.准备rpm安装包 kudu-1.4.0: kudu的基础安装包 kudu-client0-1.4.0: kudu的c++客户端共享库 kudu-client-devel-1.4.0: kudu的c++客户端共享库sdk kudu-master-1.4.0: kudu master kudu-tserver-1.4.0: kudu tserver

任意输入一个整数m,若m不是素数,则对m进行质因数分解,并以质因数从小到大顺序排列的乘积形式输出

每个合数都可以写成几个质数&#xff08;也可称为素数&#xff09;相乘的形式 &#xff0c;这几个质数就都叫做这个合数的质因数。 #include <stdio.h> int isPrime(int num)// 判断一个数是否是素数 {if (num < 2) {return 0;}for (int i 2; i * i < num; i) {…

汽车电子 -- CAN总线波特率计算方法

上一篇文章介绍 PCAN View 安装与使用 的时候&#xff0c;留下了两个问题&#xff0c;CAN总线波特率该怎么计算&#xff1f; 下图里的这些 Prescaler、tseg1、tseg2、sync Jump Width是什么意思&#xff1f; CAN2.0协议中定义标称位速率为一理想的发送器在没有重新同步的情况…

2023年毫米波行业研究报告

第一章 行业概况 1.1 定义 毫米波是一种电磁波&#xff0c;其波长范围在1毫米至10毫米之间&#xff0c;频率介于30GHz至300GHz。与sub-6G (6GHz以下频段&#xff09;的5G系统相比&#xff0c;5G毫米波通信在带宽、时延和灵活弹性空口配置方面具有明显优势。这使其能够有效地满…

风车时间锁管理 - 构建IPA文件加锁+签名+管理一站式解决方案

时间锁管理&#xff1a;是一种用于控制对某些资源、功能或操作的访问权限的机制&#xff0c;它通过设定时间限制来限制对特定内容、系统或功能的访问或执行&#xff0c;以提高安全性和控制性&#xff0c;时间锁管理常见于以下场景&#xff1a; 1. 文件或文档的保密性&#xff…

STL list

文章目录 一、list 类的模拟实现 list 是一个带头双向循环链表&#xff0c;可以存储任意类型 模板参数 T 表示存储元素的类型&#xff0c;Alloc 是空间配置器&#xff0c;一般不用传 一、list 类的模拟实现 iterator 和 const_iterator 除了下述不同外&#xff0c;其他代码基…

优优嗨聚集团:抖音外卖转为区域代理,美团外卖是否胜利

在外卖市场日益激烈的竞争中&#xff0c;抖音和美团两大巨头都有着不同的策略。近期&#xff0c;抖音外卖宣布转为区域代理模式&#xff0c;而美团外卖则持续扩大市场份额。 外卖市场近年来呈现出爆炸性增长&#xff0c;成为消费者日常生活中不可或缺的一部分。根据艾媒咨询数据…

Unity之手游UI的点击和方向移动

一 Button的点击 1.1 新建UI -> Button 1.2 在Button上面右击添加空物体 1.3 创建脚本挂载到空物体上面 脚本内容添加点击方法&#xff0c;来控制物体的显示隐藏 using System.Collections; using System.Collections.Generic; using Unity.VisualScripting; using Unit…

Keepalived+LVS负载均衡

Keepalived 是一个用于实现高可用性的开源软件&#xff0c;它基于 VRRP&#xff08;Virtual Router Redundancy Protocol&#xff09;协议&#xff0c;允许多台服务器协同工作&#xff0c;以确保在某个服务器出现故障时服务的连续性。Keepalived 的核心思想是将多台服务器配置成…

剑指offer(C++)-JZ67:把字符串转换成整数atoi(算法-模拟)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 题目描述&#xff1a; 写一个函数 StrToInt&#xff0c;实现把字符串转换成整数这个功能。不能使用 atoi 或者其他类似的库函数。…

8种LED显示屏的安装方式

LED显示屏可以根据不同的应用需求和场地条件采用多种安装方式。 LED显示屏的常见安装方式包括&#xff1a; 立柱式&#xff1a;一般多用于大厦门口、大楼大厅等户外场所&#xff0c;可以抵抗风雨侵蚀&#xff0c;更适用于户外广告牌的使用。安装方式有单立柱安装、双立柱安装和…

联合matlab和Arcgis进行netcdf格式的雪覆盖数据的重新投影栅格

图片摘要 本专栏目的是将netcdf格式的雪覆盖数据进行重新投影&#xff0c;需要使用的工具包括matlab和Arcgis&#xff0c;下面进入正题。 1.数据的下载与读取---matlab 最近我需要读取北半球的冰雪覆盖数据&#xff0c;下载的是MODIS/Terra Snow Cover Monthly L3 Global 0.0…

CPU的各种存储器接口

设计电路时往往绕不开要做一些内存或者外存的接口设计&#xff0c;比如接SDRAM、NAND FLASH等等。这些无非是为了扩展原来CPU的内存或者外存资源&#xff0c;方便运行更大的系统。比较常见的就是一些Linux的核心板。I.MX6这个就是很多产品设计中使用的。 那么&#xff0c;在这些…

uniapp 可输入可选择的........框

安装 uniapp: uni-combox地址 vue页面 <uni-combox :border"false" input"selectname" focus"handleFocus" blur"handleBlur" :candidates"candidates" placeholder"请选择姓名" v-model"name"&g…

基于JAVA+SpringBoot+Vue+协同过滤算法+爬虫的前后端分离的租房系统

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 随着城市化进程的加快…

Linux下运行Jmeter压测

一、在Linux服务器先安装SDK 1、先从官网下载jdk1.8.0_131.tar.gz&#xff0c;再从本地上传到Linux服务器 2、解压&#xff1a;tar -xzf jdk1.8.0_131.tar.gz&#xff0c;生成文件夹 jdk1.8.0_131 3、在/usr/目录下创建java文件夹&#xff0c;再将 jdk1.8.0_131目录移动到/u…

2023 Google 开发者大会:Web平台新动向

目录 前言一、Open in WordPress playground二、WebGPU三、新的核心 Web 指标INP四、Webview1、Custom Tabs2、JavaScriptEngine 五、Passkeys六、View Transitions API七、Google Chrome开发者工具优化1、覆盖HTTP的响应标头2、改变stack trance 八、Baseline总结 前言 在前不…

会员管理系统实战开发教程07-会员消费

上一篇我们讲解了会员的充值&#xff0c;会员消费和充值的逻辑类似&#xff0c;也是先记录消费金额&#xff0c;然后给会员卡余额减去消费金额&#xff0c;有个逻辑是如果余额不足需要提示信息。 1 创建消费记录表 我们先需要创建表来保存会员的消费记录信息&#xff0c;打开…

讲座2:神经编码与解码

视频来源&#xff1a; 1、面向类脑视觉的生物视觉编码机制和模型&#xff08;余肇飞&#xff09;https://www.bilibili.com/video/BV1rR4y1K7KW/?spm_id_from333.337.search-card.all.click&vd_source897075bbdd61e45006d749612d05a2ab 2、基于视觉编解码的深度学习类脑机…

7.idea 使用 docker 构建 spring boot 项目

本文目录 step 1&#xff1a;编写 Dockerfile 文件step 2&#xff1a;pom.xml 中添加如下配置step 3&#xff1a;maven仓库 setting.xml <servers> 模块下&#xff0c;添加访问自定义仓库的用户名&#xff0c;密码step 4&#xff1a;使用 maven命令开始 clean、packagest…