【设计模式】工厂方法模式详解

在java中,万物皆对象,这些对象都需要创建,如果创建的时候直接new该对象,就会对该对象耦合严重,假如我们要更换对象,所有new对象的地方都需要修改一遍,这显然违背了软件设计的开闭原则。如果我们使用工厂来生产对象,我们就只和工厂打交道就可以了彻底和对象解耦,如果要更换对象,直接在工厂里更换该对象即可,达到了与对象解耦的目目的;所以说,工厂模式最大的优点就是解耦。

简单工厂(不属于GOF23种设计模式之一):

不是一种设计模式,更像是一种编码习惯

要学习工厂方法,必须先了解什么是简单工厂

结构
  • 抽象产品:定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品:实现或者继承抽象产品的子类(即产品本身)。
  • 具体工厂:提供了创建产品的方法,调用者通过该方法来进行产品的创建
优点

封装了创建对象的过程,可以通过参数直接获取对象。把对象的创建和业务逻辑层分开,这样以后就避免了修改客户代码,如果要实产品直接修改工厂类,而不需要在原代码中修改,这样就降低了客户代码修改的可能性,更加容易扩展。

缺点

增加新产品时还是需要修改工厂类的代码,违背了“开闭原则"

// 定义一个接口或抽象类
interface Shape {void draw();
}// 定义具体的产品类
class Circle implements Shape {@Overridepublic void draw() {System.out.println("Drawing a circle...");}
}class Rectangle implements Shape {@Overridepublic void draw() {System.out.println("Drawing a rectangle...");}
}// 定义简单工厂类
class ShapeFactory {// 工厂方法,根据输入参数决定创建哪种产品public static Shape getShape(String type) {if ("circle".equalsIgnoreCase(type)) {return new Circle();} else if ("rectangle".equalsIgnoreCase(type)) {return new Rectangle();} else {throw new IllegalArgumentException("Invalid shape type: " + type);}}
}// 客户端代码
public class Client {public static void main(String[] args) {// 使用简单工厂创建不同形状的对象Shape circle = ShapeFactory.getShape("circle");circle.draw();  // 输出: Drawing a circle...Shape rectangle = ShapeFactory.getShape("rectangle");rectangle.draw();  // 输出: Drawing a rectangle...// 尝试创建无效类型try {Shape invalidShape = ShapeFactory.getShape("triangle");} catch (IllegalArgumentException e) {System.out.println(e.getMessage());}}
}

在这个例子中,ShapeFactory是简单工厂,它负责根据传入的字符串类型创建相应的形状对象。客户端代码只需调用工厂方法,不需要关心具体的创建过程。

工厂方法

针对上例中的缺点,使用工厂方法模式就可以完美的解决完全遵循开闭原则。

定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象。工厂方法使一个产品类的实例化延迟到其工厂的子类。

结构
  • 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
  • 具体工厂(Concreteractory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
  • 抽象产品(product):定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品(ConcreteProduct实现了抽象产品角色所定义的接口,由县体工厂来创建,它同县体工厂之间一一对应

将简单工厂模式升级为工厂方法模式,我们需要将创建具体产品的逻辑移到每个具体工厂类中,而不是集中在一个静态工厂方法中。以下是将简单工厂模式转换为工厂方法模式的Java代码示例:

// 定义一个接口或抽象类
interface Shape {void draw();
}// 定义具体的产品类
class Circle implements Shape {@Overridepublic void draw() {System.out.println("Drawing a circle...");}
}class Rectangle implements Shape {@Overridepublic void draw() {System.out.println("Drawing a rectangle...");}
}// 定义抽象工厂类
abstract class ShapeFactory {// 抽象工厂方法,由子类实现以创建具体产品public abstract Shape getShape();
}// 定义具体工厂类
class CircleFactory extends ShapeFactory {@Overridepublic Shape getShape() {return new Circle();}
}class RectangleFactory extends ShapeFactory {@Overridepublic Shape getShape() {return new Rectangle();}
}// 客户端代码
public class Client {public static void main(String[] args) {// 使用工厂方法模式创建不同形状的对象ShapeFactory circleFactory = new CircleFactory();Shape circle = circleFactory.getShape();circle.draw();  // 输出: Drawing a circle...ShapeFactory rectangleFactory = new RectangleFactory();Shape rectangle = rectangleFactory.getShape();rectangle.draw();  // 输出: Drawing a rectangle...// 如果需要添加更多形状,只需要创建更多的具体工厂类即可,这里不再演示创建三角形的工厂类}
}

在这个工厂方法模式的示例中,我们创建了一个抽象工厂类ShapeFactory,并在其中定义了抽象方法getShape()。然后,我们分别为每种形状创建了具体工厂类(如CircleFactory和RectangleFactory),并在这些类中实现创建相应形状对象的逻辑。客户端代码现在可以根据需求实例化不同的具体工厂类来创建所需形状对象。

优点
  1. 用户只需要知道具体工厂的名称就可得到所要的产品无须知道产品的具体创建过程
  2. 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则
缺点

每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。

典型案例 Collection.iterator
List<String> list = Arrays.asList("a","b","c","d");
Iterator<String> iterator = list.iterator();
// ArrayList部分源码
public interface AbstractList<E> extends AbstractCollection<E> implements List<E>  {// Iteratorspublic Iterator<E> iterator() {return new Itr();}public ListIterator<E> listIterator() {return listIterator(0);}public ListIterator<E> listIterator(final int index) {rangeCheckForAdd(index);return new ListItr(index);}private class Itr implements Iterator<E>{...}private class ListItr extends Itr implements ListIterator<E>{...}}
// Collection 部分源码
public interface Collection<E> extends Iterable<E> {Iterator<E> iterator();
}
// Interator部分源码
public interface Iterator<E> {boolean hasNext();E next();
}

在Collection中定义了Iterator的抽象方法,而ArrayList又继承Collection,并在类中重写了Interator的方法。
也就是说ArrayList类是在工厂类中创建了Iterator 和ListIterator 的产品。即:

  • Collection接口是抽象工厂类,
  • ArrayList是具体的工厂类;
  • Iterator接口是抽象商品类,
  • ArrayList类中的Iter和ListItr是具体的商品类。
    在具体的工厂类中iterator()方法是创建具体的商品类对象。

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

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

相关文章

STP生成树——解决二层组网环路

目录 一.二层组网环路 1.广播风暴 2.MAC地址漂移 3.有没有三层环路 二.STP生成树 &#xff08;1&#xff09;工作原理 &#xff08;2&#xff09;STP概念 1.桥ID&#xff08;BID) 2.根桥 3.COST 4.RPC 5. Rort ID ——本端 6.BPDU报文 7.PID&#xff08;Port ID&…

语音识别文字 免费 openai-whisper

语音和别文字 git地址 https://github.com/openai/whisper 简单的测试一下功能 具体使用请访问 git 环境搭建 python 环境 pip install githttps://github.com/openai/whisper.git自行安装 ffmpeg 命令行工具 测试效果 # "/Users/mac/Downloads/aad.mp3" 为本…

ARM-IIC实验

要求 设置温度湿度阈值&#xff0c;当温度过高时&#xff0c;打开风扇&#xff0c;蜂鸣器报警 当湿度比较高时&#xff0c;打开LED1灯&#xff0c;蜂鸣器报警 现象视频 IIC.mp4 代码实现 main.c #include"si7006.h" #include"led.h" #include"f…

IDC:2027年中国网络安全市场规模将超200亿美元

IDC于近日发布了2024年V1版IDC《全球网络安全支出指南》(IDC Worldwide Security Spending Guide)。IDC数据显示&#xff0c;2022年全球网络安全IT总投资规模为1890.1亿美元&#xff0c;并有望在2027年增至3288.8亿美元&#xff0c;五年复合增长率&#xff08;CAGR&#xff09;…

若依ruoyi-vue实现excel导入导出

文章目录 Excel注解excel数据导入前端实现后端实现 下载模板前端实现后端实现 excel数据导出前端实现后端实现 自定义标题信息导出用户管理表格新增标题&#xff08;用户列表&#xff09;导入表格包含标题处理方式 自定义数据处理器自定义隐藏属性列导入对象的子对象导出对象的…

FakeLocation报虚拟位置服务连接失败,请重启设备再试

虚拟位置服务连接失败&#xff0c;请重启设备再试 最近遇到一个手机软件报的bug“虚拟位置服务连接失败&#xff0c;请重启设备再试” 因为我的实体“虚拟机”已经root&#xff0c;按道理是不可能报这个错的 折腾了2天&#xff0c;终于解决了 原来是这样&#xff0c;安装最新…

龙智亮相2024国际集成电路展览会暨研讨会(IIC Shanghai),分享芯片研发及管理解决方案与技术实践

2024年3月28-29日&#xff08;周四-周五&#xff09;&#xff0c;上海张江科学会堂&#xff0c;2024国际集成电路展览会暨研讨会&#xff08;IIC Shanghai 2024&#xff09;即将盛大开幕。龙智携芯片研发及管理解决方案、最佳实践与案例&#xff0c;以及惊喜大奖在#1A14展位等着…

【C语言】数组和指针

目录 一、&数组名VS数组名 二、数组指针 三、指针数组 四、函数指针 五、const和指针 1、常量指针 六、sizeof和指针、数组 七、strlen和字符数组 八、指针和数组笔试题 1、一维数组 2、字符数组 3、二维数组 一、&数组名VS数组名 //试试这段代码 #includ…

Redis 教程系列之Redis 配置(三)

Redis 配置 Redis 的配置文件位于 Redis 安装目录下,文件名为 redis.conf(Windows 名为 redis.windows.conf)。 你可以通过 CONFIG 命令查看或设置配置项。 语法 Redis CONFIG 命令格式如下: redis 127.0.0.1:6379> CONFIG GET CONFIG_SETTING_NAME 实例 redis 127.0…

C++ 中的 unordered_map 用法文档

当你在C中需要使用哈希表&#xff08;无序映射&#xff09;来管理键值对时&#xff0c;unordered_map 是一个非常有用的数据结构。以下是关于 unordered_map 的用法&#xff1b; 1. 概述 unordered_map 是 C STL&#xff08;标准模板库&#xff09;中的一个关联容器&#xff…

二刷代码随想录——动态规划day57

文章目录 前言动态规知识点 动规五部曲一、647. 回文子串二、516. 最长回文子序列总结 前言 一个本硕双非的小菜鸡&#xff0c;备战24年秋招&#xff0c;计划二刷完卡子哥的刷题计划&#xff0c;加油&#xff01; 二刷决定精刷了&#xff0c;于是参加了卡子哥的刷题班&#xf…

数据挖掘|数据预处理|基于Python的数据标准化方法

基于Python的数据标准化方法 1. z-score方法2. 极差标准化方法3. 最大绝对值标准化方法 在数据分析之前&#xff0c;通常需要先将数据标准化&#xff08;Standardization&#xff09;&#xff0c;利用标准化后的数据进行数据分析&#xff0c;以避免属性之间不同度量和取值范围差…

15:00面试,15:06就出来了,问的问题有点变态了

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到3月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降30%…

PTA L2-032 彩虹瓶

彩虹瓶的制作过程&#xff08;并不&#xff09;是这样的&#xff1a;先把一大批空瓶铺放在装填场地上&#xff0c;然后按照一定的顺序将每种颜色的小球均匀撒到这批瓶子里。 假设彩虹瓶里要按顺序装 N 种颜色的小球&#xff08;不妨将顺序就编号为 1 到 N&#xff09;。现在工…

项目管理-需求分析

项目需求分析是项目管理中非常重要的一环&#xff0c;它涉及到对项目目标的理解、项目范围的界定、项目需求的收集、分析和整理。以下是项目需求分析的一般步骤&#xff1a; 1. 确定项目目标&#xff1a;明确项目的目的和预期成果&#xff0c;确保项目团队对项目目标有共同的认…

基于cnn卷积神经网络的yolov8动物姿态估计识别(训练代码)

往期热门项目大合集&#xff1a; 人体姿态识别&#xff08;教程代码&#xff09;-CSDN博客 3D人体姿态估计&#xff08;教程代码&#xff09;-CSDN博客 3D目标检测&#xff08;教程代码&#xff09;_3d目标检测原理-CSDN博客 交通路标识别(教程&代码)_路标识别项目概述…

【c++】类和对象(二)this指针

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好&#xff0c;本节内容来到类和对象第二篇&#xff0c;本篇文章会带领大家了解this指针 目录 1.this指针1.1this指针的引出1.2this指针的特性1.3思考题1.4C语言和C实现Stack的对…

解析option设计模式

解析option设计模式 一、背景二、应用demo三、Gin中的应用 一、背景 有时候一个函数会有很多参数&#xff0c;为了方便函数的使用&#xff0c;我们会给希望给一些参数设定默认值&#xff0c;调用时只需要传与默认值不同的参数即可。因此选项设计模式顾名思义&#xff0c;就是在…

Redis 缓存穿透是什么?如何缓解缓存穿透?

缓存穿透是指在使用缓存技术时&#xff0c;恶意或无效的请求无法从缓存中获取到数据&#xff0c;从而直接落到底层存储系统&#xff08;如数据库&#xff09;上&#xff0c;导致频繁地查询底层存储系统&#xff0c;增加系统负载并降低性能。 缓存通常用于存储经常被请求的数据…

QB 系统配置模板

查询的时候&#xff0c;直接 在下面添加 一个字段就行&#xff01; public function getDeatil(){$post $this->request->post();if(!isset($post[id])){return out(请传递活动的id);}$builder new Builder($this->getModel());$builder->setFilter([id > …