浅谈装饰模式

一、前言

        hello大家好,本次打算简单聊一下装饰者模式,其实写有关设计模式的内容还是蛮有挑战性的,首先呢就是小永哥实力有限担心说不明白,其次设计模式是为了解决某些问题场景,在当前技术生态圈如此完善的情况下,能遇到使用设计模式的时候其实还是蛮少见的,而且我一直认为解决方案本身没有好坏之分,只有经过取舍适合当前的才是最好的。任何事物都是双刃剑,包括设计模式,在没有适合场景的情况下强行使用反而会造成过度设计,这样就不好了。

        不过呢前几天小永哥确实遇到了一个小场景能用一下装饰者模式,不过作为演示呢我就不完整复刻那些复杂的代码了,咱来点简易的类比一下,尽量以少的代码能说明白。

二、业务场景

        当时的业务场景是一个Excel导入功能,我们都知道导入时,需要读取逐行读取Excel数据,每行数据又要对应列的数据读取出来赋值给实体类对象,每一行就是一个实体类对象,最后将这些实体类对象设置到提前声明好的list集合中并调用批量保存完成导入,简易导入请看下述代码。

package com.relation;import com.alibaba.fastjson2.JSON;
import org.apache.poi.ss.usermodel.*;
import org.junit.jupiter.api.Test;import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;/*** @author huhy* @version 1.0* @Description:* @ClassName Date:2025/5/10 20:20*/
public class ImportTest {@Testpublic void test() throws IOException {ArrayList<Map<String,Object>> mapList = new ArrayList<>();// 导入的源文件String path = "E:\\test\\demo.xlsx";// 工作薄对象Workbook workbook = WorkbookFactory.create(new FileInputStream(path));// 工作表 sheetSheet sheet = workbook.getSheetAt(0);// 行int rows = sheet.getPhysicalNumberOfRows();DataFormatter dataFormatter = new DataFormatter();// 行的头信息,第一行,可以不处理for (int i = 1; i < rows; i++) {Row row = sheet.getRow(i);Map<String,Object> demoData = new HashMap<>();// 第一个单元格,因为是序号,可以不要// 从第二个单元格开始获取名称String name = dataFormatter.formatCellValue(row.getCell(1));demoData.put("name",name);// 第三个单元格获取编号String code = dataFormatter.formatCellValue(row.getCell(2));demoData.put("code",code);// 把组装好的 student对象,存入集合mapList.add(demoData);}System.out.println(JSON.toJSONString(mapList));}
}

         以上就是一个简易的excel上传代码,运行测试类也能从excel中获取到数据,一个很正常和普通的小需求,想来以各位老铁的本事,这些都不叫事。下面有请我们T哥给我上点强度。

三、来自T哥的折磨

        T哥:一般找我来都没啥好事,不过能给你填点堵我还是很乐意的。

        小白:T哥你客气了,有事您吩咐,没有困难我制造困难也给你整明白儿的。

        T哥:好了,废话少说,为了减少用户手输的错误率,你看能不能给表格内容去空格呀,防止用户不小心在前后多输空格然后又检查不出来。

        小白:那太简单了,你就瞧好吧......

        3.1、去空格需求的实现。

        很简单嘛,给设置值的位置调用一下String自带的trim()方法不就好了,很轻松呀。

        3.2、来自T哥的新需求。

        T哥:这么快就实现了,不愧是专业的java开发人员,那个什么,客户要求除去空格之外,需要将每个数据都加上一个前缀AAA。这个能实现吧。

        小白:好吧,也不是什么问题。

我们可以看到小白很快又搞定了,但是小白陷入了沉思。

        小白:不对呀,为什么我每次都要改所有单元格设置的位置呢?我得想办法写个方法把这些集中起来,这样我只需要在第一次修改的时候改动位置稍微多一点,以后每次我修改集中起来的代码就好了。说干就干。

        

package com.relation;import com.alibaba.fastjson2.JSON;
import com.relation.common.utils.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.junit.jupiter.api.Test;import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;/*** @author huhy* @version 1.0* @Description:* @ClassName Date:2025/5/10 20:20*/
public class ImportTest {@Testpublic void test() throws IOException {// 将Excel文件导入到数据库中ArrayList<Map<String,Object>> mapList = new ArrayList<>();// 导入的源文件String path = "E:\\test\\demo.xlsx";// 工作薄对象Workbook workbook = WorkbookFactory.create(new FileInputStream(path));// 工作表 sheetSheet sheet = workbook.getSheetAt(0);// 行int rows = sheet.getPhysicalNumberOfRows();DataFormatter dataFormatter = new DataFormatter();// 行的头信息,第一行,可以不处理for (int i = 1; i < rows; i++) {Row row = sheet.getRow(i);Map<String,Object> demoData = new HashMap<>();// 第一个单元格,因为是序号,可以不要// 从第二个单元格开始获取名称String name = dataFormatter.formatCellValue(row.getCell(1));demoData.put("name",getStr(name));// 第三个单元格获取编号String code = dataFormatter.formatCellValue(row.getCell(2));demoData.put("code",getStr(code));// 把组装好的 student对象,存入集合mapList.add(demoData);}System.out.println(JSON.toJSONString(mapList));}private String getStr(String data){if(StringUtils.isEmpty(data)){return data;}return "AAA"+data.trim();}
}

        小白抽取了一个方法,专门用来处理表格内容,好像比之前要好很多了。

        T哥:你进步了,已经开始能自查并完善自己的代码了......

        小白:当然了,每次都改那么多地方,我累,能少改干嘛要多改呢?

        T哥:那既然你这么说,那你抽取getStr方法之后,不还是得在第一次修改的时候,逐个找到每个获取表格的位置去替换为使用getStr方法吗?

        小白:还好吧,只有两处而已,有必要再折腾吗?

        T哥:没错,现在确实是只有名称和编码两个属性,那万一有几十个属性呢?你也要一个个去修改吗?不是你自己说能少写一行代码就不多写一行吗?

        小白:那好吧,我再想想办法,毕竟我是一个面向对象工程师......

        3.3、面向对象方式改造
package com.relation;import com.relation.common.utils.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataFormatter;/*** @author huhy* @version 1.0* @Description:* @ClassName Date:2025/5/10 21:47*/
public class DataFormatterExpand extends DataFormatter {@Overridepublic String formatCellValue(Cell cell) {String cellValue = super.formatCellValue(cell);if(StringUtils.isEmpty(cellValue)){return cellValue;}return "AAA"+cellValue.trim();}
}
package com.relation;import com.alibaba.fastjson2.JSON;
import com.relation.common.utils.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.junit.jupiter.api.Test;import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;/*** @author huhy* @version 1.0* @Description:* @ClassName Date:2025/5/10 20:20*/
public class ImportTest {@Testpublic void test() throws IOException {// 将Excel文件导入到数据库中ArrayList<Map<String,Object>> mapList = new ArrayList<>();// 导入的源文件String path = "E:\\test\\demo.xlsx";// 工作薄对象Workbook workbook = WorkbookFactory.create(new FileInputStream(path));// 工作表 sheetSheet sheet = workbook.getSheetAt(0);// 行int rows = sheet.getPhysicalNumberOfRows();DataFormatterExpand dataFormatter = new DataFormatterExpand();// 行的头信息,第一行,可以不处理for (int i = 1; i < rows; i++) {Row row = sheet.getRow(i);Map<String,Object> demoData = new HashMap<>();// 第一个单元格,因为是序号,可以不要// 从第二个单元格开始获取名称String name = dataFormatter.formatCellValue(row.getCell(1));demoData.put("name",name);// 第三个单元格获取编号String code = dataFormatter.formatCellValue(row.getCell(2));demoData.put("code",name);// 把组装好的 student对象,存入集合mapList.add(demoData);}System.out.println(JSON.toJSONString(mapList));}
}

 

        我们可以看到,小白扩展了一个类并继承了DataFormatter并重写了formatCellValue方法,先调用父类的formatCellValue,然后再对获取的值进行统一扩展完成任务。

        T哥:很好,一个非常标准的OO设计。

        小白:当然了,我可是一个专业的OO程序员。

        T哥:其实做到这一步已经设计的很不错了,代码改动也少,变化的代码也抽取出去了,那还有可以改进的地方吗?

        小白:我不是很明白,现在不是很完美了吗?为什么还要改进?

        T哥:如果针对此功能需求到此为止,那你的设计可以说完美,但是如果后续还有变化呢?你还能优雅保持你的扩展性吗?

        小白:我想是可以的。

        T哥:好的,那咱们继续,

        3.4、T哥的BUFF叠加

        T哥:来新需求了,我们需要再加上BBB后缀。

        小白:这简单,我继续修改一下。

        T哥:新需求来了,要求把AAA前缀去掉......

        小白:T哥,你怕不是玩死我吧?

        T哥:你说的什么话,不是你让我来给你提需求吗?

        小白:我*******

        T哥:我*******

        然后T哥和小白打起来了.........

        小永哥:小白你先放手,这事儿哥帮你办了,你先消消气。

        3.5、小永哥的改造
package com.relation.expand;import com.relation.common.utils.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataFormatter;/*** @author huhy* @version 1.0* @Description:* @ClassName Date:2025/5/10 21:47*/
public class DataFormatterTrimExpand extends DataFormatter {private DataFormatter dataFormatter;public void setDataFormatter(DataFormatter dataFormatter) {this.dataFormatter = dataFormatter;}@Overridepublic String formatCellValue(Cell cell) {String cellValue = dataFormatter.formatCellValue(cell);if(StringUtils.isEmpty(cellValue)){return cellValue;}return cellValue.trim();}
}

        

package com.relation.expand;import com.relation.common.utils.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataFormatter;/*** @author huhy* @version 1.0* @Description:* @ClassName Date:2025/5/10 21:47*/
public class DataFormatterPrefixExpand extends DataFormatter {private DataFormatter dataFormatter;public void setDataFormatter(DataFormatter dataFormatter) {this.dataFormatter = dataFormatter;}@Overridepublic String formatCellValue(Cell cell) {String cellValue = dataFormatter.formatCellValue(cell);if(StringUtils.isEmpty(cellValue)){return cellValue;}return "AAA"+cellValue;}
}

package com.relation.expand;import com.relation.common.utils.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataFormatter;/*** @author huhy* @version 1.0* @Description:* @ClassName Date:2025/5/10 21:47*/
public class DataFormatterSuffixExpand extends DataFormatter {private DataFormatter dataFormatter;public void setDataFormatter(DataFormatter dataFormatter) {this.dataFormatter = dataFormatter;}@Overridepublic String formatCellValue(Cell cell) {String cellValue = dataFormatter.formatCellValue(cell);if(StringUtils.isEmpty(cellValue)){return cellValue;}return cellValue+"BBB";}
}
package com.relation.expand;import org.apache.poi.ss.usermodel.DataFormatter;/*** @author huhy* @version 1.0* @Description:* @ClassName Date:2025/5/10 22:27*/
public class DataFormatterFactory {public static DataFormatter createDataFormatter(){DataFormatter dataFormatter = new DataFormatter();//创建去空格扩展类DataFormatterTrimExpand dataFormatterTrimExpand = new DataFormatterTrimExpand();//创建加前缀扩展类DataFormatterPrefixExpand dataFormatterPrefixExpand = new DataFormatterPrefixExpand();//创建加后缀扩展类DataFormatterSuffixExpand dataFormatterSuffixExpand = new DataFormatterSuffixExpand();//按需求进行组合//将原生DataFormatter设置到去空格扩展类来达到去空格功能dataFormatterTrimExpand.setDataFormatter(dataFormatter);//将去空格扩展类设置到加前缀扩展类,来给去空格后的值加前缀dataFormatterPrefixExpand.setDataFormatter(dataFormatterTrimExpand);//将加前缀扩展类设置到加后缀扩展类,给加完前缀值在加上后缀dataFormatterSuffixExpand.setDataFormatter(dataFormatterPrefixExpand);return dataFormatterSuffixExpand;}
}
package com.relation;import com.alibaba.fastjson2.JSON;
import com.relation.expand.DataFormatterFactory;
import com.relation.expand.DataFormatterTrimExpand;
import org.apache.poi.ss.usermodel.*;
import org.junit.jupiter.api.Test;import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;/*** @author huhy* @version 1.0* @Description:* @ClassName Date:2025/5/10 20:20*/
public class ImportTest {@Testpublic void test() throws IOException {// 将Excel文件导入到数据库中ArrayList<Map<String,Object>> mapList = new ArrayList<>();// 导入的源文件String path = "E:\\test\\demo.xlsx";// 工作薄对象Workbook workbook = WorkbookFactory.create(new FileInputStream(path));// 工作表 sheetSheet sheet = workbook.getSheetAt(0);// 行int rows = sheet.getPhysicalNumberOfRows();DataFormatter dataFormatter = DataFormatterFactory.createDataFormatter();// 行的头信息,第一行,可以不处理for (int i = 1; i < rows; i++) {Row row = sheet.getRow(i);Map<String,Object> demoData = new HashMap<>();// 第一个单元格,因为是序号,可以不要// 从第二个单元格开始获取名称String name = dataFormatter.formatCellValue(row.getCell(1));demoData.put("name",name);// 第三个单元格获取编号String code = dataFormatter.formatCellValue(row.getCell(2));demoData.put("code",code);// 把组装好的 student对象,存入集合mapList.add(demoData);}System.out.println(JSON.toJSONString(mapList));}
}

我们可以看到,经过小永哥的改造,前缀和后缀都加上了,但是好像代码量多了很多。

        小白:永哥,你这是什么名堂,为啥你改造完以后代码量反而更多了呢?

        小永哥:你说的对,初期确实代码量比你的OO设计要多了不少,待我给你好好介绍一下。

        3.6、代码解析

        1)、如下图所示,我们为每一种扩展都创建了对应的实现类。

        2)、我们改造了扩展类,我们加了一个DataFormatter类型的成员变量,我们不再调用父类的方法,而是调用成员变量的方法。

        3)、这样做的好处是,成员变量可以是原生的类,也可是我们的扩展类,这样的话,我们就可以按照需求灵活对扩展类进行组合。

        4)、我们创建了一个简易的工厂DataFormatterFactory来生成DataFormatter,将我们组合的逻辑封装在工厂类的createDataFormatter方法中,从此刻开始,我们已经将所有变化的东西,从我们的主业务逻辑中抽取了出来。

        5)、经过一系列的改造,我们的代码可扩展性和可维护性已经大大的提高了,需求变化时,如果我们已经有对应的扩展类,则直接进行组合即可,如果没有对应的扩展类,我们可以创建新的扩展类,并进行新的组合。

        T哥:小永哥有两下子哈,小白你能总结一下你小永哥这么做符合哪些原则吗?

        小白:首先,小永哥对每一种扩展创建对应的实现类,满足了单一职责。对于新的扩展,创建新的实现类,而不对业务代码进行修改,符合开闭原则,但好像对工厂类有改动,好像又没有很完美的符合开闭原则。

        T哥:你说的很对,开闭原则是对修改关闭,对新增开放以大大减少对已有稳定代码的改动,以减少需求变化对系统的影响,但是要完全做到开闭原则很难,我们在开发过程中或多或少都会涉及到对原有代码的改动,这个是不可避免的,小永哥可以说将代码改动控制在很小范围之内了,如果出现问题,排查范围也会小很多。

        小永哥:不好意思,我插一句哈,在扩展类的改造中,我使用了组合模式,利用组合模式松耦合的特性来提升系统的弹性,小白这一点你要牢记,有时候有一个比是一个要更好,说的更直白一点,就是组合模式要比继承的灵活性更强。

        小白:永哥,我记住了。

        3.7、总结

        经过了一系列的改造,我们已经将代码改造好了,特别是最后一次改造,运用的就是经典的装饰模式。通过自由组合的方式对原始的类进行层层装饰,从而达到我们的目的。

四、结语

        又耗费了不少脑细胞,写了这么多希望可以通过这个简单的案例将装饰模式能聊清楚,装饰模式虽然很经典,但是在小永哥的心中,威力最大的还是策略模式,特别是策略模式+模版方法模式,威力巨大,能灵活多变的应对繁琐的业务变化,小永哥好好构思一下业务场景,争取下把和大家聊聊这两种设计模式以及这两种设计模式的组合体,本次就到这了,谢谢大家,晚安。

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

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

相关文章

04 mysql 修改端口和重置root密码

当我们过了一段时间&#xff0c;忘了自己当初创建的数据库密码和端口&#xff0c;或者端口被占用了&#xff0c;要怎么处理呢 首先&#xff0c;我们先停止mysql。 一、修改端口 打开my.ini文件&#xff0c;搜索port&#xff0c;默认是3306&#xff0c;根据你的需要修改为其他…

【基于 LangChain 的异步天气查询1】异步调用 Open-Meteo API 查询该城市当前气温

目录 一、功能概述 二、文件结构 三、城市天气实时查询&#xff08;运行代码&#xff09; weather_runnable.py main.py 运行结果 四、技术亮点 五、使用场景 一、功能概述 它实现了以下主要功能&#xff1a; 用户输入地点&#xff08;城市名&#xff09; 构造提示词…

Spark的三种部署模式及其特点与区别

Spark支持多种集群部署模式&#xff0c;主要分为以下三类&#xff1a; 部署模式特点适用场景资源管理依赖Local模式单机运行&#xff0c;所有进程&#xff08;Driver、Executor&#xff09;在同一个JVM中开发调试、小规模数据测试无集群资源管理&#xff0c;仅本地线程模拟无需…

再度深入理解PLC的输入输出接线

本文再次重新梳理&#xff1a; 两线式/三线式传感器的原理及接线、PLC的输入和输出接线&#xff0c;深入其内部原理&#xff0c;按照自己熟悉的方式去理解该知识 在此之前&#xff0c;需要先统一几个基础知识点&#xff1a; 在看任何电路的时候&#xff0c;需要有高低电压差&…

dockerfile编写入门

dockerfile 入门 前提已经知道常用的docker和linux命令 如容器的创建,运行, linux的文件命令,会上传文件到linux等等 dockerfile简介 之前我们所使用的镜像都是别人构建好的&#xff0c;但是别人构建好的镜像不一定能满足我们的需求。为了满足我们自己的某一些需求&#xff…

jenkins 启动报错

java.lang.UnsatisfiedLinkError: /opt/application/jdk-17.0.11/lib/libfontmanager.so: libfreetype.so.6: cannot open shared object file: No such file or directory。 解决方案&#xff1a; yum install freetype-devel 安装完成之后重启jenkins。

Harness: 全流程 DevOps 解决方案,让持续集成如吃饭般简单

引言 在当今快速发展的软件开发世界中,高效的 DevOps 工具变得越来越重要。Harness 作为一个开源的运维平台,为开发和运维团队提供了从代码托管到 CI/CD 的全流程解决方案,同时实现自动化的开发环境和制品管理。这种集中化的工具可以显著减少运维难度,提高团队效率,真正解…

Kubernetes生产实战(十七):负载均衡流量分发管理实战指南

在Kubernetes集群中&#xff0c;负载均衡是保障应用高可用、高性能的核心机制。本文将从生产环境视角&#xff0c;深入解析Kubernetes负载均衡的实现方式、最佳实践及常见问题解决方案。 一、Kubernetes负载均衡的三大核心组件 1&#xff09;Service资源&#xff1a;集群内流…

单脉冲前视成像多目标分辨算法——论文阅读

单脉冲前视成像多目标分辨算法 1. 论文的研究目标及实际意义1.1 研究目标1.2 实际问题与产业意义2. 论文的创新方法及公式解析2.1 核心思路2.2 关键公式与模型2.2.1 单脉冲雷达信号模型2.2.2 匹配滤波输出模型2.2.3 多目标联合观测模型2.2.4 对数似然函数与优化2.2.5 MDL准则目…

Java后端程序员学习前端之JavaScript

1.什么是JavaScript 1.1.概述 JavaScript是一门世界上最流行的脚本语言javaScript 一个合格的后端人员&#xff0c;必须要精通JavaScript 1.2.历史 JavaScript的起源故事-CSDN博客 2.快速入门 2.1.引入JavaScript 1.内部标签 <script>//.......</script> --…

AI编程: 使用Trae1小时做成的音视频工具,提取音频并识别文本

背景 在上个月&#xff0c;有网页咨询我怎么才能获取视频中的音频并识别成文本&#xff0c;我当时给他的回答是去问一下AI&#xff0c;让AI来给你答案。 他觉得我在敷衍他&#xff0c;大骂了我一顿&#xff0c;大家觉得我的回答对吗&#xff1f; 小编心里委屈&#xff0c;我…

AI日报 · 2025年5月10日|OpenAI“Stargate”超级数据中心项目掀起美国各州争夺战

1、OpenAI“Stargate”超级数据中心项目掀起美国各州争夺战 《华盛顿邮报》披露&#xff0c;OpenAI 与 Oracle、SoftBank 合作推进的“Stargate”项目&#xff08;首期投资 1000 亿美元&#xff0c;四年内总投资 5000 亿美元&#xff09;已收到超过 250 份选址提案&#xff…

Windows系统Jenkins企业级实战

目标 在Windows操作系统上使用Jenkins完成代码的自动拉取、编译、打包、发布工作。 实施 1.安装Java开发工具包&#xff08;JDK&#xff09; Jenkins是基于Java的应用程序&#xff0c;因此需要先安装JDK。可以从Oracle官网或OpenJDK下载适合的JDK版本。推荐java17版本&#x…

MySQL 索引和事务

目录 一、MySQL 索引介绍 1、索引概述 2、索引作用 3、索引的分类 &#xff08;1&#xff09;普通索引 &#xff08;2&#xff09;唯一索引 &#xff08;3&#xff09;主键索引 &#xff08;4&#xff09;组合索引&#xff08;最左前缀&#xff09; &#xff08;5&…

Block Styler——字符串控件

字符串控件的应用 参考官方帮助案例&#xff1a;&#xff08;这个方式感觉更好&#xff0c;第二种方式也可以&#xff09;E:\NX1980\UGOPEN\SampleNXOpenApplications\C\BlockStyler\ColoredBlock 普通格式&#xff1a; 读取&#xff1a; //方法一 string0->GetProperti…

P2572 [SCOI2010] 序列操作 Solution

Description 给定 01 01 01 序列 a ( a 1 , a 2 , ⋯ , a n ) a(a_1,a_2,\cdots,a_n) a(a1​,a2​,⋯,an​)&#xff0c;并定义 f ( l , r ) [ ( ∑ i l r a i ) r − l 1 ] f(l,r)[(\sum\limits_{il}^r a_i)r-l1] f(l,r)[(il∑r​ai​)r−l1]. 执行 m m m 个操作&am…

RAG 2.0 深入解读

作者&#xff1a;阿里云开发者 原文&#xff1a;https://zhuanlan.zhihu.com/p/1903437079603545114​ 一、Introduction 过去一年可谓是RAG元年&#xff0c;检索增强生成技术迅速发展与深刻变革&#xff0c;其创新与应用已深刻重塑了大模型落地的技术范式。站在2025年&#x…

代码随想录第41天:图论2(岛屿系列)

一、岛屿数量&#xff08;Kamacoder 99&#xff09; 深度优先搜索&#xff1a; # 定义四个方向&#xff1a;右、下、左、上&#xff0c;用于 DFS 中四向遍历 direction [[0, 1], [1, 0], [0, -1], [-1, 0]]def dfs(grid, visited, x, y):"""对一块陆地进行深度…

基于CNN的猫狗图像分类系统

一、系统概述 本系统是基于PyTorch框架构建的智能图像分类系统&#xff0c;专门针对CIFAR-10数据集中的猫&#xff08;类别3&#xff09;和狗&#xff08;类别5&#xff09;进行分类任务。系统采用卷积神经网络&#xff08;CNN&#xff09;作为核心算法&#xff0c;结合图形用…

linux搭建hadoop学习

linux搭建hadoop学习 下载安装包: 海外资源可能需要翻墙或者找国内资源 cd /opt wget https://dlcdn.apache.org/hadoop/common/hadoop-2.10.2/hadoop-2.10.2.tar.gz tar -zxvf hadoop-2.10.2.tar.gz mv hadoop-2.10.2 hadoop配置环境变量 # 在/etc/profile文件中添加下面内…