java设计模式-工厂模式(上)

什么是工厂模式

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

工厂模式提供了一种将对象的实例化过程封装在工厂类中的方式。通过使用工厂模式,可以将对象的创建与使用代码分离,提供一种统一的接口来创建不同类型的对象。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

工厂模式可以分为三类:简单工厂模式(静态工厂模式)、工厂方法模式 和 抽象工厂模式。

其中简单工厂模式,严格上来说,不属于23设计模式之一,因为它违背了开闭原则,更好的是看作为一种编程方式。

本篇中会介绍三种工厂的使用,也就是

  • 简单(静态)工厂模式(不属于GOF的23种经典设计模式)
  • 工厂方法模式
  • 抽象工厂模式

使用场景

日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。

数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。

等等。。。

下面我们模拟手机工厂生产手机。。。

核心角色

  • 抽象产品:定义了产品的共同接口或抽象类。它可以是具体产品类的父类或接口,规定了产品对象的共同方法。
  • 具体产品:实现了抽象产品接口,定义了具体产品的特定行为和属性。
  • 抽象工厂:声明了创建产品的抽象方法,可以是接口或抽象类。它可以有多个方法用于创建不同类型的产品。
  • 具体工厂:实现了抽象工厂接口,负责实际创建具体产品的对象。

1.简单(静态)工厂模式

实现了抽象工厂接口,负责实际创建具体产品的对象。

结构

简单工厂包含如下角色:

  • 抽象产品:定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品:实现或者继承抽象产品的子类
  • 具体工厂:提供了创建产品的方法,调用者通过该方法来获取产品。

示例

模拟手机工厂生产手机。

我们需要定义一个抽象手机产品,定义手机产品的品牌和颜色两个方法

/*** 手机产品抽象类** @author jiangkd* @date 2023/7/28 14:03:15*/
public abstract class AbstractPhone {/*** 手机品牌*/public abstract void brand();/*** 手机颜色*/public abstract void color();}

然后有两个具体产品,一加和真我,哈哈哈

/*** 具体手机产品, 一加手机** @author jiangkd* @date 2023/7/28 14:06:17*/
@Slf4j
public class YijiaPhone extends AbstractPhone {@Overridepublic void brand() {log.info("品牌, 一加手机!!!");}@Overridepublic void color() {log.info("黑色!!!");}}
/*** 具体手机产品, 真我手机** @author jiangkd* @date 2023/7/28 14:07:27*/
@Slf4j
public class ZhenwoPhobe extends AbstractPhone {@Overridepublic void brand() {log.info("品牌, 真我手机!!!");}@Overridepublic void color() {log.info("白色!!!");}}

产品有了,现在我们创建一个手机工厂,可以根据不同参数创建不同品牌手机

/*** 手机产品的工厂** @author jiangkd* @date 2023/7/28 14:09:50*/
public class PhoneFactory {/*** 具体如何产生一个产品的对象,是由具体的工厂类实现的* <p>* 注意, 这里是静态方法** @param clazz* @return AbstractPhone* @throws Exception e*/public static AbstractPhone createPhone(Class clazz) throws Exception {// 全限定类名final String name = clazz.getName();// 根据反射, 创建具体产品对象return (AbstractPhone) Class.forName(name).newInstance();}/*** 当前方法其实和createPhone方法是一样的作用, 两个方法用哪个都可以* <p>* 注意, 这里是静态方法** @param brand 根据参数区分创建哪个具体产品* @return AbstractPhone*/public static AbstractPhone createPhone2(String brand) throws Exception {if (CharSequenceUtil.equals("yijia", brand)) {return new YijiaPhone();} else if (CharSequenceUtil.equals("zhenwo", brand)) {return new ZhenwoPhobe();} else {throw new Exception("参数异常!!!");}}}

测试一下

/*** @author jiangkd* @date 2023/7/28 14:17:25*/
@Slf4j
public class DemoTest {public static void main(String[] args) throws Exception {// 创建一加手机AbstractPhone yijiaPhone = PhoneFactory.createPhone(YijiaPhone.class);yijiaPhone.brand();yijiaPhone.color();log.info("--------------------------------");yijiaPhone = PhoneFactory.createPhone2("yijia");yijiaPhone.brand();yijiaPhone.color();log.info("--------------------------------");// 创建真我手机AbstractPhone zhenwoPhone = PhoneFactory.createPhone(ZhenwoPhobe.class);zhenwoPhone.brand();zhenwoPhone.color();log.info("--------------------------------");zhenwoPhone = PhoneFactory.createPhone2("zhenwo");zhenwoPhone.brand();zhenwoPhone.color();}}

运行结果如下:

14:19:59.846 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.YijiaPhone - 品牌, 一加手机!!!
14:19:59.851 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.YijiaPhone - 黑色!!!
14:19:59.851 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.DemoTest - --------------------------------
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.YijiaPhone - 品牌, 一加手机!!!
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.YijiaPhone - 黑色!!!
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.DemoTest - --------------------------------
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.ZhenwoPhobe - 品牌, 真我手机!!!
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.ZhenwoPhobe - 白色!!!
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.DemoTest - --------------------------------
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.ZhenwoPhobe - 品牌, 真我手机!!!
14:19:59.882 [main] INFO demo.basic.example.design_patterns.gcms.jdgcms.ZhenwoPhobe - 白色!!!

其实可以看出来,这里我们只有两个具体的手机产品,简答(静态)工厂模式还是很方便的,但你有没有发现,如果现在我陆陆续续追加其他具体产品 红米!努比亚!荣耀!那么我就要陆陆续续三次修改手机工厂类(追加具体产品不算修改,是扩展功能)的功能,这显然不符合java设计模式的六大原则-开闭原则。

那不如我们把工厂拆开,每个工厂只生产一种具体的手机产品,这样如果我需要增加一个红米,就只需要添加一个红米工厂和一个红米产品类就可以了,这就是接下来要演示的工厂方法模式

2.工厂方法模式

简单工厂模式确实很方便,但是每次新增一个手机产品都需要改动整个工厂的原有代码,现在使用工厂方法模式改造一下。

抽象手机产品AbstractPhone 和 两个具体的手机产品(一加,真我)不变,依然如上。

工厂类PhoneFactory不要了,我们需要重新创建工厂类。

现在我们首先创建一个抽象工厂类,用来生产AbstractPhone

/*** 定义产品的抽象工厂类** @author jiangkd* @date 2023/7/28 14:43:04*/
public abstract class AbstractPhoneFactory {/*** 构建产品, 具体实现交给子类** @return AbstractPhone*/abstract AbstractPhone createPhone();}

然后分别是一加手机和真我手机的两个具体工厂实现类,每个实现类针对一个具体手机品牌的生产

/*** 具体产品一加手机的工厂实现类** @author jiangkd* @date 2023/7/28 14:44:53*/
public class YijiaPhoneFactory extends AbstractPhoneFactory {@OverrideAbstractPhone createPhone() {return new YijiaPhone();}}
/*** 具体产品真我手机的工厂实现类** @author jiangkd* @date 2023/7/28 14:45:35*/
public class ZhenwoPhoneFactory extends AbstractPhoneFactory {@OverrideAbstractPhone createPhone() {return new ZhenwoPhobe();}}

测试一下

/*** @author jiangkd* @date 2023/7/28 14:46:16*/
@Slf4j
public class DemoTest {public static void main(String[] args) {// 生产一加手机final AbstractPhoneFactory yijiaPhoneFactory = new YijiaPhoneFactory();final AbstractPhone yijiaPhone = yijiaPhoneFactory.createPhone();yijiaPhone.brand();yijiaPhone.color();log.info("--------------------------------");// 生产真我手机final AbstractPhoneFactory zhenwoPhoneFactory = new ZhenwoPhoneFactory();final AbstractPhone zhenwoPhone = zhenwoPhoneFactory.createPhone();zhenwoPhone.brand();zhenwoPhone.color();}}

运行结果如下:

14:48:22.596 [main] INFO demo.basic.example.design_patterns.gcms.YijiaPhone - 品牌, 一加手机!!!
14:48:22.598 [main] INFO demo.basic.example.design_patterns.gcms.YijiaPhone - 黑色!!!
14:48:22.598 [main] INFO demo.basic.example.design_patterns.gcms.gcffms.DemoTest - --------------------------------
14:48:22.599 [main] INFO demo.basic.example.design_patterns.gcms.ZhenwoPhobe - 品牌, 真我手机!!!
14:48:22.599 [main] INFO demo.basic.example.design_patterns.gcms.ZhenwoPhobe - 白色!!!

现在我们如果想要加一个红米手机,只需要创建具体红米产品和对应的工厂类就可以了

/*** 具体手机产品 红米** @author jiangkd* @date 2023/7/28 14:51:09*/
@Slf4j
public class HongmiPhone extends AbstractPhone {@Overridepublic void brand() {log.info("品牌, 红米手机!!!");}@Overridepublic void color() {log.info("红色!!!");}}
/*** 红米手机工厂实现类** @author jiangkd* @date 2023/7/28 14:52:04*/
public class HongmiPhoneFactory extends AbstractPhoneFactory {@OverrideAbstractPhone createPhone() {return new HongmiPhone();}}

测试

/*** @author jiangkd* @date 2023/7/28 14:46:16*/
@Slf4j
public class DemoTest {public static void main(String[] args) {// 生产一加手机final AbstractPhoneFactory yijiaPhoneFactory = new YijiaPhoneFactory();final AbstractPhone yijiaPhone = yijiaPhoneFactory.createPhone();yijiaPhone.brand();yijiaPhone.color();log.info("--------------------------------");// 生产真我手机final AbstractPhoneFactory zhenwoPhoneFactory = new ZhenwoPhoneFactory();final AbstractPhone zhenwoPhone = zhenwoPhoneFactory.createPhone();zhenwoPhone.brand();zhenwoPhone.color();log.info("--------------------------------");// 生产红米手机final AbstractPhoneFactory hongmiPhoneFactory = new HongmiPhoneFactory();final AbstractPhone hongmiPhone = hongmiPhoneFactory.createPhone();hongmiPhone.brand();hongmiPhone.color();}}

执行结果

14:53:43.272 [main] INFO demo.basic.example.design_patterns.gcms.YijiaPhone - 品牌, 一加手机!!!
14:53:43.274 [main] INFO demo.basic.example.design_patterns.gcms.YijiaPhone - 黑色!!!
14:53:43.274 [main] INFO demo.basic.example.design_patterns.gcms.gcffms.DemoTest - --------------------------------
14:53:43.276 [main] INFO demo.basic.example.design_patterns.gcms.ZhenwoPhobe - 品牌, 真我手机!!!
14:53:43.276 [main] INFO demo.basic.example.design_patterns.gcms.ZhenwoPhobe - 白色!!!
14:53:43.276 [main] INFO demo.basic.example.design_patterns.gcms.gcffms.DemoTest - --------------------------------
14:53:43.276 [main] INFO demo.basic.example.design_patterns.gcms.HongmiPhone - 品牌, 红米手机!!!
14:53:43.276 [main] INFO demo.basic.example.design_patterns.gcms.HongmiPhone - 红色!!!

符合开闭原则,不修改原来的功能,只是添加产品和工厂类就可以了。

细心的小伙伴又会问了,虽然不用在原基础功能上修改,但是如果还要添加10个品牌手机,岂不是要加10个产品类和10个工厂类,增加维护难度呀!是的,这就是工厂方法模式的弊端,增加系统的复杂度。

所以你可以看出,简单(静态)工厂和工厂方法模式,都是针对一类产品的生产,也就是这些工厂只生产同种类产品,同种类产品称为同等级产品。(工厂方法模式只考虑生产同等级的产品)

但实际上呢,现实生活中许多工厂是综合型的工厂,能生产多等级(种类) 的产品,如电器厂既生产电视机又生产洗衣机或空调,大学既有软件专业又有生物专业等。

这就是下面的抽象工厂模式了。。。,我们继续延申,现在老板发话了,生产手机的时候,顺便把耳机也生产出来吧

3.抽象工厂模式

由于篇幅问题,继续查看java设计模式-工厂模式(下)

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

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

相关文章

LeetCode32.Longest-Valid-Parentheses<最长有效括号>

题目&#xff1a; 思路&#xff1a; 遍历括号.遇到右括号然后前一个是左括号 那就res2,然后重定位 i 的值 并且长度减少2; 但是问题在于无法判断最长的括号.只能得到string内的全部括号长度. 错误代码: 写过一题类似的,那题是找括号数.记得是使用的栈,但是死活写不出来. 看完…

Dubbo 指定调用固定ip+port dubbo调用指定服务 dubbo调用不随机 dubbo自定义调用服务 dubbo点对点通信 dubbo指定ip

1. 在写分布式im时nami-im: 分布式im, 集群 zookeeper netty kafka nacos rpc主要为gate&#xff08;长连接服务&#xff09; logic &#xff08;业务&#xff09; lsb &#xff08;负载均衡&#xff09;store&#xff08;存储&#xff09; - Gitee.com&#xff0c;需要指定某一…

[ 容器 ] Docker Compose 编排

目录 Docker Compose 环境安装下载安装查看版本YAML 文件格式及编写注意事项使用 YAML 时需要注意下面事项 Docker Compose配置常用字段Docker Compose 常用命令Docker Compose 文件结构 Docker Compose 环境安装 Docker Compose 是 Docker 的独立产品&#xff0c;因此需要安装…

当机器人变硬核:探索深度学习中的时间序列预测

收藏自&#xff1a;Wed, 15 Sep 2021 10:32:56 UTC 摘要&#xff1a;时间序列预测是机器学习和深度学习领域的一个重要应用&#xff0c;它可以用于预测未来趋势、分析数据模式和做出决策。本文将介绍一些基本概念和常用方法&#xff0c;并结合具体的案例&#xff0c;展示如何使…

React Native 0.72 版本,带来诸多更新

经过漫长的等待,React Native 终于迎来了0.72 版本,此处版本带来了Metro重要的功能更新、性能优化、开发人员体验的改进以及其他一些重要的变化。我们可以从下面的链接中获取此次版本更新的内容:0.72更新内容 一、Metro 新功能 众所周知,Metro 是 React Native 默认的 Jav…

idea插件开发-自定义语言4-Syntax Highlighter

SyntaxHighlighter用于指定应如何突出显示特定范围的文本&#xff0c;ColorSettingPage可以定义颜色。 一、Syntax Highter 1、文本属性键&#xfeff; TextAttributesKey用于指定应如何突出显示特定范围的文本。不同类型的数据比如关键字、数字、字符串等如果要突出显示都需…

代码-【5 二叉树非递归后序遍历,找指定结点的父节点】

二叉树T按二叉链表存储&#xff0c;求指定结点q的父节点&#xff1a;

【Ubuntu系统18.04虚拟机ros下实现darknet_ros(YOLO V3)检测问题解析最全】

原本打算在搭载Ubuntu18.04的智能小车上面运行使用darknet_ros 包来进行yolov3的检测&#xff0c;但是运行过程中遇到了不少问题&#xff0c;从头到尾部的运行包括遇到的解决方法以及对应的文章一并列出&#xff0c;免得到处查找。 首先是在ROS下实现darknet_ros(YOLO V3)检测…

浅谈自动化测试

谈谈那些实习测试工程师应该掌握的基础知识&#xff08;一&#xff09;_什么时候才能变强的博客-CSDN博客https://blog.csdn.net/qq_17496235/article/details/131839453谈谈那些实习测试工程师应该掌握的基础知识&#xff08;二&#xff09;_什么时候才能变强的博客-CSDN博客h…

使用克拉默法则进行三点定圆(二维)

目录 1.二维圆2.python代码3.计算结果 本文由CSDN点云侠原创&#xff0c;爬虫网站请自重。 1.二维圆 已知不共线的三个点&#xff0c;设其坐标为 ( x 1 , y 1 ) (x_1,y_1) (x1​,y1​)、 ( x 2 , y 2 ) (x_2,y_2) (x2​,y2​)、 ( x 3 , y 3 ) (x_3,y_3) (x3​,y3​)&#xf…

FSM:Full Surround Monodepth from Multiple Cameras

参考代码&#xff1a;None 介绍 深度估计任务作为基础环境感知任务&#xff0c;在基础上构建的3D感知才能更加准确&#xff0c;并且泛化能力更强。单目的自监督深度估计已经有MonoDepth、ManyDepth这些经典深度估计模型了&#xff0c;而这篇文章是对多目自监督深度估计进行探…

使用云服务器和Frp(快速反向代理)框架快速部署实现内网穿透

目录 一. 背景1.1 内网穿透1.2 Frp介绍1.3 Frp配置流程 二. 云服务器配置2.1 配置安全组2.2 编写frps.ini 三. 内网主机配置3.1 编辑frpc.ini文件3.2 启动服务并配置开机自启动 四. 参考文献 一. 背景 现在有一台ubuntu云服务器&#xff0c;我想通过内网穿透将一台内网的主机当…

RocketMQ 5.1.0 源码详解 | Producer 启动流程

文章目录 初始化DefaultMQProducer实例启动流程DefaultMQProducer#startDefaultMQProducerImpl#startMQClientInstance#start启动流程总结 实例内容 初始化DefaultMQProducer实例 初始化一个 DefaultMQProducer 对象的代码如下 // 返回一个producer对象 DefaultMQProducer pr…

[SQL挖掘机] - 转换机制

一种较为有用的数据转换机制是在查询中修改列的数据类型. 通常, 当处理不同数据类型(如数字)的列时, 可使用仅对一种数据类型(如文本)有效的函数. 当修改某一列的数据类型时, 可简单地采用 column::datatype 格式. 其中, column表示为列名, datatype 表示为将列调整后的数据类型…

python多线程

目录 一.多线程的定义 A.什么是多线程&#xff1f; B.多线程如今遇到的挑战 C.总结 二.python中的多线程 A.python中的多线程底层原理&#xff1a; B.全局解释器锁导致python多线程不能实现真正的并行执行&#xff01; C.总结应用场景 三.java多线程&#xff0c;以及…

【Matlab】判断点和多面体位置关系的两种方法实现

我的主页&#xff1a; 技术邻&#xff1a;小铭的ABAQUS学习的技术邻主页博客园 : HF_SO4的主页哔哩哔哩&#xff1a;小铭的ABAQUS学习的个人空间csdn&#xff1a;qgm1702 博客园文章链接&#xff1a; https://www.cnblogs.com/aksoam/p/17590039.html 分别是向量判别法&…

Ubuntu 22.04下对无线网络作静态ip设置

内容如题所示&#xff0c;最近本人安全毕业&#xff0c;参加工作了&#xff0c;此处应有鲜花和掌声&#xff0c;哈哈哈。但新的生活总是有很多的小问题&#xff0c;坎坎坷坷&#xff0c;所以&#xff0c;我继续记录工作和学习生活中遇到的问题。 今天带我的云哥给了我一个ip&am…

Python入门【变量的作用域(全局变量和局部变量)、参数的传递、浅拷贝和深拷贝、参数的几种类型 】(十一)

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱敲代码的小王&#xff0c;CSDN博客博主,Python小白 &#x1f4d5;系列专栏&#xff1a;python入门到实战、Python爬虫开发、Python办公自动化、Python数据分析、Python前后端开发 &#x1f4e7;如果文章知识点有错误…

无涯教程-jQuery - wrapInner( html )方法函数

wrapInner(html)方法使用HTML结构包装每个匹配元素(包括文本节点)的内部子内容。 wrapInner( html ) - 语法 selector.wrapInner( html ) 这是此方法使用的所有参数的描述- html - 将动态创建并环绕目标的HTML字符串。 wrapInner( html ) - 示例 以下是一个简单的示例…

Jupyter Notbook无法刷新.bashrc中的环境变量

Jupyter Notbook无法刷新.bashrc中的环境变量 原因解决方法 原因 在Linux系统中&#xff0c;在.bashrc中添加环境变量后&#xff0c;打开jupyter notebook发现无法加载添加的环境变量。这是因为.bashrc只对bash起作用&#xff0c;如果使用GUI软件直接访问&#xff0c;是无法加…