设计模式Java实现-工厂模式

news2024/12/24 20:31:59

✨这里是第七人格的博客✨小七,欢迎您的到来~✨

🍅系列专栏:设计模式🍅

✈️本篇内容: 工厂模式✈️

🍱本篇收录完整代码地址:https://gitee.com/diqirenge/design-pattern 🍱

楔子

记得刚入行的时候,听过一个段子,同样开发一个功能初级程序员要1天,中级程序员要2天,高级程序员要1个星期。当时以为是老油条划水(虽然肯定还是会划一点水,哈哈),但是其实更重要的还是设计思想的不同,经验丰富的程序员往往考虑的更多,不光是业务拓展性,更有程序拓展性。

需求背景

实现一个图片上传功能,逻辑很简单,就是把图片上传到对象存储,但是现在有两个服务商可以选择,他们分别是阿里云和腾讯云,并且现在没有敲定用哪一个,需要你先对接。他们提供的API各不相同,我们假设他们提供的API如下

渠道接口
阿里云void aliUpload(String fileName, String ossId, String token);
腾讯云String tencentUpload(String fileName, String base64, String appID, String appSecret);

分析设计

因为这2个接口的实现的定义不一样,所以我们最好能抽象出一个统一的接口,让子类去实现自己的业务逻辑,这样的好处是以后腾讯云有变更,就改腾讯云,阿里云有变更就改阿里云,两个子类互不影响(满足单一职责原则)。

又为了不让上层直接使用我们这个统一的方法,所以我们可以再抽象一个类,让他来决定用哪一个上传方式,相当于加了一层防腐,这里我们把他叫做工厂类(创建者与具体的业务解耦)。

再想一下拓展情况,如果以后又加一种上传方式,比如华为云,那我们修改起来也非常方便,只要再加一个子类就可以了,调用方可以不用变(满⾜开闭原则)。

UML图

根据分析设计,我们可以先画一个简单的UML图,后面通过UML图编码

工厂模式UML.png

模块名称

factory

模块地址

https://gitee.com/diqirenge/design-pattern/tree/master/src/main/java/com/run2code/design/creational/factory

模块描述

工厂模式代码示例

代码实现

1、首先我们模拟出两个外部接口

上传至oss

/**
 * 上传至oss
 * 关注公众号【奔跑的码畜】,一起进步不迷路
 *
 * @author 第七人格
 * @date 2023/11/17
 */
public class AliOss {
    public void aliUpload(String fileName, String ossId, String token) {
        System.out.println("ali upload 入参: " + fileName + " " + ossId + " " + token);
        System.out.println("ali 上传成功!");
    }
}

上传至cos

/**
 * 上传至cos
 * 关注公众号【奔跑的码畜】,一起进步不迷路
 *
 * @author 第七人格
 * @date 2023/11/17
 */
public class TencentCos {
    public String tencentUpload(String fileName, String base64, String appID, String appSecret) {
        System.out.println("tencent upload 入参: " + fileName + " " + base64 + " " + appID + " " + appSecret);

        return "成功上传到腾讯云";
    }
}

2、然后定义一个用于创建对象的接口或抽象类,让子类决定实例化哪一个类

抽象类

/**
 * 抽象的上传操作类,当然他也可以是一个接口
 * 关注公众号【奔跑的码畜】,一起进步不迷路
 *
 * @author 第七人格
 * @date 2023/11/15
 */
public abstract class BaseUpDownloader {
    /**
     * 执行文件上传操作(延迟到子类实现)
     *
     * @param filePath 文件路径
     * @param fileName 文件名称
     * @param param    第三方参数
     * @return {@link String}
     */
    public abstract String doUpload(String filePath, String fileName, Map<String, String> param);
}

上传子类 oss,继承了抽象类,并且调用了上传至oss的方法

/**
 * 上传子类 oss
 * 关注公众号【奔跑的码畜】,一起进步不迷路
 *
 * @author 第七人格
 * @date 2023/11/15
 */
public class AliOssUpDownloader extends BaseUpDownloader {

    private AliOss aliOss;

    public AliOssUpDownloader() {
        this.aliOss = new AliOss();
    }

    @Override
    public String doUpload(String filePath, String fileName, Map<String, String> param) {
        aliOss.aliUpload(fileName, param.get("ossId"), param.get("token"));
        return "AliOssUpDownloader upload success";
    }
}

上传子类 cos,继承了抽象类,并且调用了上传至oss的方法

/**
 * 上传子类 cos,继承了抽象类,并且调用了上传至oss的方法
 * 关注公众号【奔跑的码畜】,一起进步不迷路
 *
 * @author 第七人格
 * @date 2023/11/15
 */
public class TencentUpDownloader extends BaseUpDownloader {

    private TencentCos tencentCos;

    public TencentUpDownloader() {
        this.tencentCos = new TencentCos();
    }

    @Override
    public String doUpload(String filePath, String fileName, Map<String, String> param) {
        String result = tencentCos.tencentUpload(fileName, param.get("base64"), param.get("appID"), param.get("appSecret"));
        System.out.println(result);
        return "TencentUpDownloader upload success";
    }
}

3、创建一个工厂类,其中包含一个用于创建产品对象的方法。

/**
 * 上传的工厂类
 * 关注公众号【奔跑的码畜】,一起进步不迷路
 *
 * @author 第七人格
 * @date 2023/11/17
 */
public class UpDownloaderFactory {
    /**
     * 注册上传下载对象到工厂。
     *
     * @param upDownloaderName 下载器名称
     * @return {@link BaseUpDownloader}
     */
    public BaseUpDownloader registerUpDownloader(String upDownloaderName) {
        if ("tencent".equalsIgnoreCase(upDownloaderName)) {
            return new TencentUpDownloader();
        } else if ("ali".equalsIgnoreCase(upDownloaderName)) {
            return new AliOssUpDownloader();
        }
        return null;
    }
}

4、编写测试方法

/**
 * 测试工厂模式
 * 关注公众号【奔跑的码畜】,一起进步不迷路
 *
 * @author 第七人格
 * @date 2023/11/17
 */
public class UpDownloaderFactoryTest {

    /**
     * 测试调用阿里上传
     */
    @Test
    public void testAli() {
        UpDownloaderFactory factory = new UpDownloaderFactory();
        BaseUpDownloader upDownloader = factory.registerUpDownloader("ali");

        Map<String, String> param = new HashMap<>();
        param.put("ossId", "ossId");
        param.put("token", "token");

        if (upDownloader == null) {
            return;
        }

        System.out.println("==========上传开始==========");
        String result = upDownloader.doUpload("/temp/file", "阿里文件.pdf", param);
        System.out.println("结果:" + result);
        System.out.println("==========上传结束==========");
    }

    /**
     * 测试调用腾讯上传
     */
    @Test
    public void testTencent() {
        UpDownloaderFactory factory = new UpDownloaderFactory();
        BaseUpDownloader upDownloader = factory.registerUpDownloader("tencent");

        Map<String, String> param = new HashMap<>();
        param.put("base64", "base64");
        param.put("appID", "appID");
        param.put("appSecret", "appSecret");

        if (upDownloader == null) {
            return;
        }

        System.out.println("==========上传开始==========");
        String result = upDownloader.doUpload("/temp/file", "腾讯文件.pdf", param);
        System.out.println("结果:" + result);
        System.out.println("==========上传结束==========");
    }

}

5、测试结果

①执行testAli方法

==========上传开始==========

ali upload 入参: 阿里文件.pdf ossId token

ali 上传成功!

结果:AliOssUpDownloader upload success

==========上传结束==========

②执行testTencent方法

==========上传开始==========

tencent upload 入参: 腾讯文件.pdf base64 appID appSecret

成功上传到腾讯云

结果:TencentUpDownloader upload success

==========上传结束==========

实现要点

  1. 定义一个用于创建对象的接口或抽象类,让子类决定实例化哪一个类。

    示例中为:BaseUpDownloader

  2. 创建一个工厂类,其中包含一个用于创建产品对象的方法。

    示例中,工厂类为:UpDownloaderFactory;创建产品对象的方法为:registerUpDownloader

  3. 在客户端代码中,通过调用工厂类的方法来创建所需的产品对象,而无需直接调用具体的产品类的构造函数。

    示例中为:

    UpDownloaderFactory factory = new UpDownloaderFactory();

    BaseUpDownloader upDownloader = factory.registerUpDownloader("ali");

总结

本文从模拟需求开始,带着读者一起学习了工厂模式,从上文可知工厂模式其实非常简单,掌握三大实现要点就可以了。所以小七在工作中使用工厂模式的频率也非常的高,但是工厂模式一般是不会单独使用的,他的好伙伴有策略模式、单例模式、模版模式等等,后面小七都会讲到。

本文由博客一文多发平台 OpenWrite 发布!

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

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

相关文章

JVM之内存分配的详细解析

内存分配 两种方式 不分配内存的对象无法进行其他操作&#xff0c;JVM 为对象分配内存的过程&#xff1a;首先计算对象占用空间大小&#xff0c;接着在堆中划分一块内存给新对象 如果内存规整&#xff0c;使用指针碰撞&#xff08;Bump The Pointer&#xff09;。所有用过的内…

快速入门!学习鸿蒙App开发的终极指南!

鸿蒙&#xff08;HarmonyOS&#xff09;是华为推出的一款分布式操作系统&#xff0c;旨在为不同设备提供统一的操作体验。鸿蒙App开发可以让应用程序在多个设备上实现流畅运行。本文将介绍鸿蒙App开发的终极指南&#xff0c;帮助您快速入门。 开发环境搭建 鸿蒙App开发过程需要…

R语言Rstudio突然无法启动?如何解决

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

fiscobcos 3.x linux安装与java简单调用

所用环境 vmware 16 Pro centos7.6 jdk11.0.6 ideal 2022 1、安装fiscobcos # 创建操作目录 # cd ~ && mkdir -p fisco && cd fisco# 下载建链脚本 # curl -#LO https://github.com/FISCO-BCOS/FISCO-BCOS/releases/download/v3.6.0/build_chain.sh &a…

知识图谱在提升大语言模型性能中的应用:减少幻觉与增强推理的综述

幻觉现象指的是模型在生成文本时可能会产生一些听起来合理但实际上并不准确或相关的输出&#xff0c;这主要是由于模型在训练数据中存在知识盲区所致。 为了解决这一问题&#xff0c;研究人员采取了多种策略&#xff0c;其中包括利用知识图谱作为外部信息源。知识图谱通过将信息…

Kalign 3:大型数据集的多序列比对

之前一直用的是muscle&#xff0c;看到一个文章使用了Kalign&#xff0c;尝试一下吧 安装 wget -c https://github.com/TimoLassmann/kalign/archive/refs/tags/v3.4.0.tar.gz tar -zxvf v3.4.0.tar.gz cd kalign-3.4.0 mkdir build cd build cmake .. make make test su…

OpenNJet:云原生技术中的创新者与实践者

目录 引言OpenNJet介绍OpenNJet优势1. 性能无损动态配置2. 灵活的CoPilot框架3. 支持HTTP/34. 支持国密5. 企业级应用6. 高效安全 OpenNJet 编译与安装环境准备编译环境配置配置yum源yum 安装软件包创建符号连接修改 ld.so.conf 配置 编译代码 部署 WEB SERVER配置OpenNJet部署…

Unity 性能优化之遮挡剔除(Occlusion Culling)(六)

提示&#xff1a;仅供参考&#xff0c;有误之处&#xff0c;麻烦大佬指出&#xff0c;不胜感激&#xff01; 文章目录 前言一、遮挡剔除是什么&#xff1f;二、静态遮挡剔除的使用步骤1.标记为遮挡剔除对象2.创建Occlusion Area组件3.烘焙4.Occlusion窗口Bake的参数Smallest Oc…

linux实验(数据库备份)

以下所有操作皆以机房电脑上的虚拟机为基础环境 下载链接&#xff1a;Linux课程机房虚拟机# 切换到root用户 su - root安装数据库mysql 5.7 rpm -ivh https://mirrors4.tuna.tsinghua.edu.cn/mysql/yum/mysql-5.7-community-el7-x86_64/mysql-community-common-5.7.29-1.el7.x…

ROS 2边学边练(43)-- 利用GTest写一个基本测试(C++)

前言 在ROS&#xff08;Robot Operating System&#xff09;中&#xff0c;gtest&#xff08;Google Test&#xff09;是一个广泛使用的C测试框架&#xff0c;用于编写和执行单元测试。这些测试可以验证ROS节点、服务和消息等的正确性和性能。 如果我们需要在写的包中添加测试&…

严苛工作环境下IMU的最佳选择—爱普生M-G364及M-G354

爱普生(EPSON)秉持其省、小、精的核心技术&#xff0c;并运用长期于工业市场中所累积的专业经验与知识&#xff0c;专注于研发符合市场需求的IMU产品&#xff0c;打造出即使在具高挑战性的严苛环境下&#xff0c;亦可提供优异稳定性及高分辨率的IMU产品。随着自主精密农业机械、…

echars设置渐变颜色的方法

在我们日常的开发中&#xff0c;难免会遇到有需求&#xff0c;需要使用echars设置渐变的图表&#xff0c;如果我们需要设置给图表设置渐变颜色的话&#xff0c;我们只需要在 series 配置项中 添加相应的属性配置项即可。 方式一&#xff1a;colorStops type&#xff1a;‘lin…

jenkins常用插件之Filesystem Trigger

安装插件 Filesystem Trigger 项目配置 验证 根据上述配置&#xff0c;当1.txt文件发生变化时&#xff0c;jenkins每分钟会进行检测&#xff0c;检测到后即进行任务构建&#xff0c;后续的具体操作可自行配置

C++ 如何进阶?

一、C基础&#xff08;3个月&#xff09; 1、面向对象的三大特性&#xff1a;封装、继承、多态 2、类的访问权限&#xff1a;private、protected、public 3、类的构造函数、析构函数、赋值函数、拷贝函数 4、移动构造函数与接贝构造函数对比 5、深接贝与浅贝的区别 6、空…

为什么相同内核的Linux桌面稳定干净,而Android却臃肿不堪?

在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「 Linux的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01; 对于这个问题&#xff0c;我…

每日一题 盛最多水的容器

. - 力扣&#xff08;LeetCode&#xff09; 思路分析: 利用函数的单调性解决这道题两端取最小&#xff0c;最小的往里找就是高不变或者缩小 宽减少 一定是减小的因此这题可以使用左右指针实现 public int maxArea(int[] height) {int left 0;int right height.length - 1;i…

红日靶场ATTCK 1通关攻略

环境 拓扑图 VM1 web服务器 win7&#xff08;192.168.22.129&#xff0c;10.10.10.140&#xff09; VM2 win2003&#xff08;10.10.10.135&#xff09; VM3 DC win2008&#xff08;10.10.10.138&#xff09; 环境搭建 win7&#xff1a; 设置内网两张网卡&#xff0c;开启…

TC3xx MTU概述(2)

目录 1.概述 2.如何配置NDT 3.小结 1.概述 上篇TC3xx MTU概述(1)-CSDN博客我们讲解了MTU基本功能和MBIST基本概念&#xff0c;接下来我们继续讲解MTU如何配置NDT算法。 2.如何配置NDT 前面聊了那么多概念&#xff0c;我们还是来看看如何配置MTU来实现NDT。 MTU寄存器分为…

为什么需要自动化测试?自动化有哪些优势?

前言 自动化测试&#xff0c;最近些年可谓是大火。招聘上的要求也好&#xff0c;培训班的广告也罢&#xff0c;比比皆是&#xff0c;足以说明它在业内的火爆程度。 虽然说会写自动化测试并不能说明你就很牛批&#xff0c;但是你不会的话&#xff0c;那么很抱歉&#xff0c;你…

如何复制本地docker镜像到其他主机

&#xff08;1&#xff09;打包镜像 比如我要复制的镜像是grafana的镜像 docker images 这里我把打包的镜像放在了根~目录下&#xff0c;如截图所示&#xff1a; docker save grafana/grafana:latest -o ~/grafana.jar &#xff08;2&#xff09;移动镜像 scp命令拷贝镜像到目标…