【设计模式】工厂模式

news2024/10/2 16:20:30

工厂模式

所谓工厂,顾名思义,就是创建出一类相似的产品的,工厂模式可以帮我们创建各个复杂/简单对象。属于创建型模式。

工厂模式分为三类:

  • 简单工厂
  • 工厂方法
  • 抽象工厂

简单工厂

比方说我们需要根据配置文件去解析配置,不同后缀名的文件需要使用不同的解析器去解析,我们当然可以将所有的代码写在一个方法里
也可以使用简单工厂,将根据文件后缀名选择解析器的逻辑封装在工厂类中

定义一个IConfigParser接口,然后定义三个不同的解析器
在这里插入图片描述

public interface IConfigParser {
    Config parse(String configText);
}
public class JsonConfigParser implements IConfigParser{

    @Override
    public Config parse(String configText) {
        return new Config("json配置文件");
    }
}
public class PropertiesConfigParser implements IConfigParser{

    @Override
    public Config parse(String configText) {
        return new Config("properties配置文件");
    }
}

public class XmlConfigParser implements IConfigParser{

    @Override
    public Config parse(String configText) {
        return new Config("xml配置文件");
    }
}

public class ConfigParserFactory {

    public static IConfigParser createParser(String configFormat) {
        if ("json".equalsIgnoreCase(configFormat)) {
            return new JsonConfigParser();
        } else  if ("xml".equalsIgnoreCase(configFormat)) {
            return new XmlConfigParser();
        } else  if ("properties".equalsIgnoreCase(configFormat)) {
            return new PropertiesConfigParser();
        }
        return null;
    }
}
public class Config {

    private String name;

    public Config(String name) {
        this.name = name;
    }
}

工厂方法模式

简单工厂适合于创建逻辑比较的场景,如果每个解析器的构建过程都十分复杂,那是不是有一个单独的工厂类去创建各自的解析器会更合适。为了去除上面if … else …的分支判断,我们将工厂对象提前缓存好,其类图如下:
在这里插入图片描述

将上述代码重构后:

public interface IConfigParserFactory {
    IConfigParser createParse();
}

public class JsonConfigParserFactory implements IConfigParserFactory{

    @Override
    public IConfigParser createParse() {
        return new JsonConfigParser();
    }
}

public class XmlConfigParserFactory implements IConfigParserFactory{

    @Override
    public IConfigParser createParse() {
        return new XmlConfigParser();
    }
}

public class Test {

    private static final Map<String, IConfigParserFactory> factoryMap = new HashMap<>();

    static {
        factoryMap.put("json", new JsonConfigParserFactory());
        factoryMap.put("xml", new XmlConfigParserFactory());
    }

    public static void main(String[] args) {
        IConfigParser configParser = factoryMap.get("json").createParse();
        Config config = configParser.parse("{}");
    }
}

抽象工厂

抽象工厂模式与工厂方法模式的最大区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则需要面对多个产品等级结构。

在学习抽象工厂具体实例之前,应该明白两个重要的概念:产品族和产品等级
所谓产品族,是指位于不同产品等级结构中,功能相关联的产品组成的家族。

以现实生活中的产品为例,我们有洗衣机,电风扇等电器,每种电器有各自的厂商,比方说美的的洗衣机、风扇,小米的洗衣机、风扇。我们认为一个品牌生产的东西是一个产品族的(美的的洗衣机和风扇都属于美的产品族),不同工厂生产的一类产品认为是一个产品等级结构的。

而所谓的抽象工厂,就是提供一个创建一系列相关或者相互依赖的对象的接口。在抽象工厂中,每一个产品族都有一个具体工厂,而每一个具体工厂负责创建属于同一个产品族,但是属于不同产品等级结构的产品。

回到前面配置解析的例子,不同的文件格式的解析器不一样,但是相同的配置文件(eg,json配置文件)在不同的系统和不同的规则下的解析器也不一样。如果按照工厂方法模式的方式来实现,给每个文件格式和系统,规则都创建Factory接口,那么我们就需要创建N*N个工厂类了,这样代码就太臃肿了。

我们可以让一个工厂来帮忙创建不同的对象(Json工厂可以帮我们创建对应的system解析器和规则解析器)

实现如下:

public interface IConfigParserFactory {

    IRuleConfigParser createRuleParse();

    ISystemConfigParser createSystemParse();

}
public interface IRuleConfigParser {

    Config parse(String configText);
}
public interface ISystemConfigParser {

    Config parse(String configText);
}

public class JsonConfigParserFactory implements IConfigParserFactory {

    @Override
    public IRuleConfigParser createFileParse() {
        return new JsonRuleConfigParser();
    }

    @Override
    public ISystemConfigParser createSystemParse() {
        return new JsonSystemConfigParser();
    }
}
public class XmlConfigParserFactory implements IConfigParserFactory {

    @Override
    public IRuleConfigParser createFileParse() {
        return new XmlRuleConfigParser();
    }

    @Override
    public ISystemConfigParser createSystemParse() {
        return new XmlSystemConfigParser();
    }
}

总结:

简单工厂 :专门定义一个类(Factory)来负责创建其它类的实例,被创建的实例通常都具有共同的父类或实现同一个接口。
​工厂(方法)模式:定义一个用于创建对象的接口(工厂接口IConfigParserFactory),让子类或实现去决定实例化哪个类。
抽象工厂模式 :提供接口给客户端用以创建一系列相关或者相互依赖的对象(往往会有一个可以创建多个产品等级结构的产品的工厂)

使用场景:

  1. 如果代码中存在大量 if-else 分⽀判断,需要动态地根据不同的类型创建不同的对象。这种情形我们就可以考虑使用工厂模式,将创建的逻辑抽离出来,放到工厂类中

  2. 不需要根据不同类型创建不同的对象,但是如果对象的创建过程十分复杂,那么我们也可以将其 创建过程封装到工厂类中

如果创建逻辑比较简单,那么直接使用简单工厂就可以了;如果创建逻辑比较复杂,那么就建议使用工厂方法模式

工厂模式的作⽤⽆外乎下⾯四个。这也是判断要不要使⽤⼯⼚模式的最本质的参考标准。

  1. 封装变化:创建逻辑有可能变化,封装成⼯⼚类之后,创建逻辑的变更对调⽤者透明。
  2. 代码复⽤:创建代码抽离到独⽴的⼯⼚类之后可以复⽤。
  3. 隔离复杂性:封装复杂的创建逻辑,调⽤者⽆需了解如何创建对象。
  4. 控制复杂度:将创建代码抽离出来,让原本的函数或类职责更单⼀,代码更简洁。

实际使用的时候不必太在意使用的究竟是简单工厂还是工厂方法或者抽象工厂,只要通过工厂模式可以使我们的代码易于扩展和维护就好了,没必要过度设计。

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

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

相关文章

html5播放器禁止拖拽、视频禁止拖动的实例

阿酷TONY / 2023-3-8 / 长沙html5播放器禁止拖拽功能,常用于场景&#xff1a;企业培训、在线教学内容禁止学员拖动视频进行观看。应用代码实例&#xff1a;<div id"player"></div> <script src"//player.polyv.net/script/player.js">&l…

pytest初识

一、单元测试框架 &#xff08;1&#xff09;什么是单元测试框架&#xff1f; 单元测试是指在软件开发中&#xff0c;针对软件的最小单元&#xff08;函数、方法&#xff09;进行正确性的检查测试 &#xff08;2&#xff09;单元测试框架 java&#xff1a;junit和testng pytho…

Windows SSH 配置和SCP的使用

使用用户界面安装 ssh 功能 要在 Windows 10/11 上启用 SSH 服务器&#xff0c;请按照以下步骤操作&#xff1a; 按“Windows 键 I”打开“设置”菜单&#xff0c;然后选择“应用程序”。在左侧菜单栏中选择“应用和功能”。从列表中选择“可选功能”。 点击“添加功能”按钮…

[数据结构]:15-堆排序(顺序表指针实现形式)(C语言实现)

目录 前言 已完成内容 堆排序实现 01-开发环境 02-文件布局 03-代码 01-主函数 02-头文件 03-PSeqListFunction.cpp 04-SortCommon.cpp 05-SortFunction.cpp 结语 前言 此专栏包含408考研数据结构全部内容&#xff0c;除其中使用到C引用外&#xff0c;全为C语言代码…

android h5考勤管理系统myeclipse开发mysql数据库编程服务端java计算机程序设计

一、源码特点 android h5考勤管理系统是一套完善的WEBandroid设计系统&#xff0c;对理解JSP java&#xff0c;安卓app编程开发语言有帮助&#xff08;系统采用web服务端APP端 综合模式进行设计开发&#xff09;&#xff0c;系统具有完整的源代 码和数据库&#xff0c;系统主…

平板触控笔要原装的吗?开学季必备电容笔推荐

如今对那些把ipad当做学习工具的用户而言&#xff0c;Apple Pencil就显得尤为重要了。但由于Apple Pencil的售价实在太高&#xff0c;让学生党望而却步。因此&#xff0c;最好的办法就是选择平替电容笔。我是一个ipad设备的忠实用户&#xff0c;同时也是一个数码热衷者&#xf…

MySQL增量备份和全量备份

1 全量备份 1.1 创建用于备份的目录 mkdir /root/mysql.backup1.2 创建存入备份文件的目录 mkdir /root/mysql.backup/data1.3 进入备份目录&#xff0c;创建备份脚本 cd /root/mysql.backupvim mysqlBackuoShell.sh#!/bin/bash #保存备份个数,31条 number31 #备份保存路…

Infineon Aurix 系列网络安全概述

目录 硬件安全 其它 1999年&#xff0c;英飞凌推出了第一代AUDO(汽车统一处理器)系列。基于统一的以RISC/MCU/DSP处理器为核心&#xff0c;这款32位TriCore™微控制器是一款强大的计算机器。其不断改进和优化TriCore的概念&#xff0c;最终形成了现在的第六代TriCore™,由于其…

ACWING蓝桥杯每日一题python(持续更新

ACWing蓝桥杯每日一题 一直没时间去总结算法&#xff0c;终于有空可以总结一下刷的acwing了&#xff0c;因为没时间所以最近只刷了ACWING的蓝桥杯每日一题。。。真是该死 1.截断数组 首先我们要知道&#xff0c;如果sum(a)不能被3整除或者len(a) < 3 &#xff0c;那么他肯…

Android使用移动智能终端补充设备标识获取OAID

官网http://www.msa-alliance.cn/col.jsp?id120首先到官网注册账号&#xff0c;申请下载相关sdk和授权证书2.把 oaid_sdk_x.x.x.aar 拷贝到项目的 libs 目录&#xff0c;并设置依赖&#xff0c;其中x.x.x 代表版本号3.supplierconfig.json 拷贝到项目 assets 目录下&#xff0…

keepalived实现nginx高可用

文章目录前言keepalived简介软件架构简单理解环境准备一、keepalived安装1.1 下载keepalived 安装包1.2 解压/下载依赖1.3 编译1.4 创建软连接1.5 增加系统服务1.6 启动keepalived二、实现Nginx高可用2.1 创建keepalived配置文件2.2 Nginx监控脚本2.4 重启keepalived2.5 查看虚…

自己DIY装机后,如何使用U盘装系统

最近自己整了一台主机&#xff0c;然后需要装一下系统&#xff0c;这边就讲一下如何用U盘给新电脑装系统。 安装Windows 10 光盘映像 首先你需要一个内存大于8GB的U盘&#xff0c;并且是纯净的&#xff0c;里面没有东西。 这边以Windows 10 为例&#xff1a; 百度搜索 下载…

IMX6ULL 启动方式之启动设备的选择

一. 硬件启动方式选择 汇编程序启动 LED 灯实验&#xff0c;是从SD卡读取 bin 文件并启动&#xff0c;说明 IMX6ULL 支持从 SD 卡启动。 IMX6ULL 支持多种启动方式。 注意&#xff1a;硬件原理图中&#xff0c;标注 DNP ( do not pupulate) 的意思是不焊接&#xff0c;即没…

【AcWing】归并排序及其应用

&#x1f386;音乐分享 &#xff08;点击链接可以听哦&#x1f60e;&#xff09; 无名之辈 - 陈雪燃 目录 归并排序 归并排序应用 文章中的图片来源&#xff1a; (2条消息) 归并排序&#xff08;分治法&#xff09;_分治法 归并排序_小小的香辛料的博客-CSDN博客 AcWing…

Springboot怎么实现WebSocket通信(二)

前言上一篇文章分享了单机模式下&#xff0c;websocket的基本使用方法&#xff0c;但在实际的业务中&#xff0c;通常是不会这样使用的&#xff0c;大部项目都是分布式部署的&#xff0c;一个工程布署了多个服务节点&#xff0c;前端并不直接请求具体服务节点&#xff0c;而是先…

C51---PWM 脉冲宽度调制

1.PWM:脉冲宽度调制,它是通过一系列脉冲宽度进行调制&#xff0c;等效出所需要的波形&#xff08;包含形状以及幅值&#xff09;。对模拟信号电平进行数字编码。也就是说通过调节占空比的变化来调节信号、能量等的变化&#xff0c;占空比就是指在一个周期内&#xff0c;信号处于…

第九届省赛——6打印大X

题目&#xff1a;本题目要求你在控制台输出一个由数字组成的等腰三角形。具体的步骤是&#xff1a;1. 先用1,2,3&#xff0c;...的自然数拼一个足够长的串2. 用这个串填充三角形的三条边。从上方顶点开始&#xff0c;逆时针填充。比如&#xff0c;当三角形高度是8时&#xff1a…

【Java开发】JUC进阶 06:异步回调、JMM、Volatile

1 异步回调异步是多线程的一种特殊实现方式&#x1f4cc; 举例我需要一个计算时间5秒方法的返回值我不想等这5秒钟&#xff0c;我想要继续执行下面的代码&#xff0c;那就异步执行这个方法当我通过get去获取这个返回值时&#xff0c;如果已经过了5秒&#xff0c;也就是方法执行…

16、参数估计

概率基本定义先验分布&#xff1a;似然函数&#xff1a;后验分布&#xff1a;贝叶斯公式&#xff1a;&#xff0c;其中后验分布 似然函数 先验分布 / P(D)贝叶斯公式假设&#xff0c;现在有两个一定概率发生的事件A和B&#xff0c;且它们之间存在一定的关系P(A) 表示事件A发生…

UNIX网络编程卷一 学习笔记 第八章 基本UDP套接字编程

UDP是无连接不可靠的数据报协议&#xff0c;不同于TCP提供的面向连接的可靠字节流。使用UDP编写的常见程序有&#xff1a;DNS、NFS、SNMP。 以下是典型的UDP客户/服务器程序的函数调用&#xff0c;客户不与服务器建立连接&#xff0c;而是只使用sendto函数给服务器发送数据报&…