2024050802-重学 Java 设计模式《实战模板模式》

重学 Java 设计模式:实战模版模式「模拟爬虫各类电商商品,生成营销推广海报场景」

一、前言

黎明前的坚守,的住吗?

有人举过这样一个例子,先给你张北大的录取通知书,但要求你每天5点起床,12点睡觉😪,刻苦学习,勤奋上进。只要你坚持三年,这张通知书就有效。如果是你,你能坚持吗?其实对于这个例子很难在我们的人生中出现,因为它目标明确,有准确的行军路线。就像你是土豪家庭,家里给你安排的明明白白一样,只要你按照这个方式走就不会有问题。可大多数时候我们并没有这样的路线,甚至不知道多久到达自己的黎明。但!谁又不渴望见到黎明呢,坚持吧!

不要轻易被洗脑

键盘侠⌨网络喷壶,几乎当你努力坚持一件事的时候,在这条路上会遇到形形色色的人和事。有时候接收建议完善自己是有必要的,但不能放弃自己的初心和底线,有时候只坚持自己也是难能可贵的。子路之勇,子贡之辩,冉有之智,此三子者,皆天下之所谓难能而可贵者也。阳光和努力是这个世界最温暖的东西,加油坚持好自己的选的路。

有时还好坚持了

当你为自己的一个决定而感到万分开心😄时,是不是也非常感谢自己还好坚持了。坚持、努力、终身学习,似乎在程序员这个行业是离不开的,当你意愿于把这当做一份可以努力的爱好时,你就会愿意为此而努力。而我们很难说只在机会要来时准备,而是一直努力等待机会。也就是很多人说的别人抓住机会是因为一直在准备着。

二、开发环境

  1. JDK 1.8
  2. Idea + Maven
  3. 涉及工程三个,可以通过关注公众号bugstack虫洞栈,回复源码下载获取(打开获取的链接,找到序号18)
工程描述
itstack-demo-design-21-00场景模拟工程;模拟爬虫商品生成海报场景

三、模版模式介绍

模版模式,图片来自 refactoringguru.cn

  • 图片来自:https://refactoringguru.cn/design-patterns/template-method

模板模式的核心设计思路是通过在,抽象类中定义抽象方法的执行顺序,并将抽象方法设定为只有子类实现,但不设计独立访问的方法。简单说也就是把你安排的明明白白的。

西游记,孙悟空打妖怪

就像西游记的99八十一难,基本每一关都是;师傅被掳走、打妖怪、妖怪被收走,具体什么妖怪你自己定义,怎么打你想办法,最后收走还是弄死看你本事,我只定义执行顺序和基本策略,具体的每一难由观音来安排。

四、案例场景模拟

场景模拟;爬虫电商商品,组装优惠推广

在本案例中我们模拟爬虫各类电商商品,生成营销推广海报场景

关于模版模式的核心点在于由抽象类定义抽象方法执行策略,也就是说父类规定了好一系列的执行标准,这些标准的串联成一整套业务流程。

在这个场景中我们模拟爬虫爬取各类商家的商品信息,生成推广海报(海报中含带个人的邀请码)赚取商品返利。声明,这里是模拟爬取,并没有真的爬取

而整个的爬取过程分为;模拟登录、爬取信息、生成海报,这三个步骤,另外;

  1. 因为有些商品只有登录后才可以爬取,并且登录可以看到一些特定的价格这与未登录用户看到的价格不同。
  2. 不同的电商网站爬取方式不同,解析方式也不同,因此可以作为每一个实现类中的特定实现。
  3. 生成海报的步骤基本一样,但会有特定的商品来源标识。所以这样三个步骤可以使用模版模式来设定,并有具体的场景做子类实现。

五、模版模式搭建工程

模版模式的业务场景可能在平时的开发中并不是很多,主要因为这个设计模式会在抽象类中定义逻辑行为的执行顺序。一般情况下,我们用的抽象类定义的逻辑行为都比较轻量级或者没有,只是提供一些基本方法公共调用和实现。

但如果遇到适合的场景使用这样的设计模式也是非常方便的,因为他可以控制整套逻辑的执行顺序和统一的输入、输出,而对于实现方只需要关心好自己的业务逻辑即可。

而在我们这个场景中,只需要记住这三步的实现即可;模拟登录爬取信息生成海报

1. 工程结构

itstack-demo-design-21-00
└── src├── main│   └── java│       └── org.itstack.demo.design│           ├── group│           │	  ├── DangDangNetMall.java│           │	  ├── JDNetMall.java│           │	  └── TaoBaoNetMall.java│           ├──  HttpClient.java│           └──  NetMall.java└── test└── java└── org.itstack.demo.design.test└── ApiTest.java

模版模式模型结构

模版模式模型结构

  • 以上的代码结构还是比较简单的,一个定义了抽象方法执行顺序的核心抽象类,以及三个模拟具体的实现(京东淘宝当当)的电商服务。

2. 代码实现

2.1 定义执行顺序的抽象类
/*** 基础电商推广服务* 1. 生成最优价商品海报* 2. 海报含带推广邀请码*/
public abstract class NetMall {protected Logger logger = LoggerFactory.getLogger(NetMall.class);String uId;   // 用户IDString uPwd;  // 用户密码public NetMall(String uId, String uPwd) {this.uId = uId;this.uPwd = uPwd;}/*** 生成商品推广海报** @param skuUrl 商品地址(京东、淘宝、当当)* @return 海报图片base64位信息*/public String generateGoodsPoster(String skuUrl) {if (!login(uId, uPwd)) return null;             // 1. 验证登录Map<String, String> reptile = reptile(skuUrl);  // 2. 爬虫商品return createBase64(reptile);                   // 3. 组装海报}// 模拟登录protected abstract Boolean login(String uId, String uPwd);// 爬虫提取商品信息(登录后的优惠价格)protected abstract Map<String, String> reptile(String skuUrl);// 生成商品海报信息protected abstract String createBase64(Map<String, String> goodsInfo);}
  • 这个类是此设计模式的灵魂
  • 定义可被外部访问的方法generateGoodsPoster,用于生成商品推广海报
  • generateGoodsPoster 在方法中定义抽象方法的执行顺序 1 2 3 步
  • 提供三个具体的抽象方法,让外部继承方实现;模拟登录(login)、模拟爬取(reptile)、生成海报(createBase64)
2.2 模拟爬虫京东
public class JDNetMall extends NetMall {public JDNetMall(String uId, String uPwd) {super(uId, uPwd);}public Boolean login(String uId, String uPwd) {logger.info("模拟京东用户登录 uId:{} uPwd:{}", uId, uPwd);return true;}public Map<String, String> reptile(String skuUrl) {String str = HttpClient.doGet(skuUrl);Pattern p9 = Pattern.compile("(?<=title\\>).*(?=</title)");Matcher m9 = p9.matcher(str);Map<String, String> map = new ConcurrentHashMap<String, String>();if (m9.find()) {map.put("name", m9.group());}map.put("price", "5999.00");logger.info("模拟京东商品爬虫解析:{} | {} 元 {}", map.get("name"), map.get("price"), skuUrl);return map;}public String createBase64(Map<String, String> goodsInfo) {BASE64Encoder encoder = new BASE64Encoder();logger.info("模拟生成京东商品base64海报");return encoder.encode(JSON.toJSONString(goodsInfo).getBytes());}}
  • 模拟登录
  • 爬取信息,这里只是把title的信息爬取后的结果截取出来。
  • 模拟创建base64图片的方法
2.3 模拟爬虫淘宝
public class TaoBaoNetMall extends NetMall {public TaoBaoNetMall(String uId, String uPwd) {super(uId, uPwd);}@Overridepublic Boolean login(String uId, String uPwd) {logger.info("模拟淘宝用户登录 uId:{} uPwd:{}", uId, uPwd);return true;}@Overridepublic Map<String, String> reptile(String skuUrl) {String str = HttpClient.doGet(skuUrl);Pattern p9 = Pattern.compile("(?<=title\\>).*(?=</title)");Matcher m9 = p9.matcher(str);Map<String, String> map = new ConcurrentHashMap<String, String>();if (m9.find()) {map.put("name", m9.group());}map.put("price", "4799.00");logger.info("模拟淘宝商品爬虫解析:{} | {} 元 {}", map.get("name"), map.get("price"), skuUrl);return map;}@Overridepublic String createBase64(Map<String, String> goodsInfo) {BASE64Encoder encoder = new BASE64Encoder();logger.info("模拟生成淘宝商品base64海报");return encoder.encode(JSON.toJSONString(goodsInfo).getBytes());}}
  • 同上,模拟登录和爬取以及创建图片的base64
2.4 模拟爬虫当当
public class DangDangNetMall extends NetMall {public DangDangNetMall(String uId, String uPwd) {super(uId, uPwd);}@Overridepublic Boolean login(String uId, String uPwd) {logger.info("模拟当当用户登录 uId:{} uPwd:{}", uId, uPwd);return true;}@Overridepublic Map<String, String> reptile(String skuUrl) {String str = HttpClient.doGet(skuUrl);Pattern p9 = Pattern.compile("(?<=title\\>).*(?=</title)");Matcher m9 = p9.matcher(str);Map<String, String> map = new ConcurrentHashMap<String, String>();if (m9.find()) {map.put("name", m9.group());}map.put("price", "4548.00");logger.info("模拟当当商品爬虫解析:{} | {} 元 {}", map.get("name"), map.get("price"), skuUrl);return map;}@Overridepublic String createBase64(Map<String, String> goodsInfo) {BASE64Encoder encoder = new BASE64Encoder();logger.info("模拟生成当当商品base64海报");return encoder.encode(JSON.toJSONString(goodsInfo).getBytes());}}
  • 同上,模拟登录和爬取以及创建图片的base64

3. 测试验证

3.1 编写测试类
/*** 测试链接* 京东;https://item.jd.com/100008348542.html* 淘宝;https://detail.tmall.com/item.htm* 当当;http://product.dangdang.com/1509704171.html*/
@Test
public void test_NetMall() {NetMall netMall = new JDNetMall("1000001","*******");String base64 = netMall.generateGoodsPoster("https://item.jd.com/100008348542.html");logger.info("测试结果:{}", base64);
}
  • 测试类提供了三个商品链接,也可以是其他商品的链接
  • 爬取的过程模拟爬取京东商品,可以替换为其他商品服务new JDNetMallnew TaoBaoNetMallnew DangDangNetMall
3.2 测试结果
23:33:13.616 [main] INFO  org.itstack.demo.design.NetMall - 模拟京东用户登录 uId:1000001 uPwd:*******
23:33:15.038 [main] INFO  org.itstack.demo.design.NetMall - 模拟京东商品爬虫解析:【AppleiPhone 11Apple iPhone 11 (A2223) 128GB 黑色 移动联通电信4G手机 双卡双待【行情 报价 价格 评测】-京东 | 5999.00 元 https://item.jd.com/100008348542.html
23:33:15.038 [main] INFO  org.itstack.demo.design.NetMall - 模拟生成京东商品base64海报
23:33:15.086 [main] INFO  org.itstack.demo.design.test.ApiTest - 测试结果:eyJwcmljZSI6IjU5OTkuMDAiLCJuYW1lIjoi44CQQXBwbGVpUGhvbmUgMTHjgJFBcHBsZSBpUGhv
bmUgMTEgKEEyMjIzKSAxMjhHQiDpu5HoibIg56e75Yqo6IGU6YCa55S15L+hNEfmiYvmnLog5Y+M
5Y2h5Y+M5b6F44CQ6KGM5oOFIOaKpeS7tyDku7fmoLwg6K+E5rWL44CRLeS6rOS4nCJ9Process finished with exit code 0

六、总结

  • 通过上面的实现可以看到模版模式在定义统一结构也就是执行标准上非常方便,也就很好的控制了后续的实现者不用关心调用逻辑,按照统一方式执行。那么类的继承者只需要关心具体的业务逻辑实现即可。
  • 另外模版模式也是为了解决子类通用方法,放到父类中设计的优化。让每一个子类只做子类需要完成的内容,而不需要关心其他逻辑。这样提取公用代码,行为由父类管理,扩展可变部分,也就非常有利于开发拓展和迭代。
  • 但每一种设计模式都有自己的特定场景,如果超过场景外的建设就需要额外考虑🤔其他模式的运用。而不是非要生搬硬套,否则自己不清楚为什么这么做,也很难让后续者继续维护代码。而想要活学活用就需要多加练习,有实践的经历。

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

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

相关文章

Proteus 新建工程

Proteus 新建工程 新建简单工程 首先在File工具栏中点击New Project&#xff0c;弹出新建工程向导程序(New Proteus Wizard) 填写工程名称与存储路径&#xff0c;选择New Proteus并点击Next进行下一步设置 我们不需要生成PCB文件&#xff0c;一路默认&#xff0c;点击Next即…

实战计算机网络02——物理层

实战计算机网络02——物理层 1、物理层实现的功能2、数据与信号2.1 数据通信模型2.2 通信领域常用术语2.3 模拟信号和数字信号 3、信道和调制3.1 信道3.2 单工通信、半双工通信、全双工通信3.3 调制3.4 奈式准则3.5 香农定律 4、传输媒体4.1 导向传输媒体4.2 非导向传输媒体 5、…

高级人工智能复习 题目整理 中科大

题目整理 填空 1.准确性&#xff0c;复杂性&#xff0c;验证集 2. 3 2 n 3^{2^n} 32n 3 C 2 n m 3^{C^m_{2n}} 3C2nm​ 3 m 3^m 3m n 1 n1 n1 3. 状态 从状态s采取行动a后继续采用策略 π \pi π的收益 环境 4. 语法 语义 推理规则 5. 参与者&#xff0c;策略集&#xff…

Elasticsearch 8.1官网文档梳理 - 十一、Ingest pipelines(管道)

Ingest pipelines 管道&#xff08;Ingest pipelines&#xff09;可让让数据在写入前进行常见的转换。例如可以利用管道删除文档&#xff08;doc&#xff09;的字段、或从文本中提取数据、丰富文档&#xff08;doc&#xff09;的字段等其他操作。 管道&#xff08;Ingest pip…

VirtualBox、Centos7下安装docker后pull镜像问题、ftp上传文件问题

Docker安装篇(CentOS7安装)_docker 安装 centos7-CSDN博客 首先&#xff0c;安装docker可以根据这篇文章进行安装&#xff0c;安装完之后&#xff0c;我们就需要去通过docker拉取相关的服务镜像&#xff0c;然后安装相应的服务容器&#xff0c;比如我们通过docker来安装mysql,…

vue 使用 ztree 超大量数据,前端树形结构展示

ztree 是一个很经典的基于jquey开发的树结构编辑展示UI组件库。 创建一个文件 ztree.vue&#xff0c;代码如下&#xff1a; <template><div><div class"ztree vue-giant-tree" :id"ztreeId"></div><div class"treeBox&q…

Termius安装docker

安装Termius 直接上官网 新建主机 更新一下yum 更新完成 安装docker的包 直接用命令安装 设置一下开机启动&#xff0c;可以查看docker的版本

Ui学习--UITableView

UI学习 UITableView基础UITableView协议UITableView高级协议与单元格总结 UITableView基础 UITableView作为iOS中的一个控件&#xff0c;用于以表格形式展示数据。例如通讯录好友&#xff0c;朋友圈信息等&#xff0c;都是UITableView的实际运用场景。 首先我们先要加入两个协…

K210使用雷龙NAND完成火灾检测

NAND 文章目录 NAND前言一、NAND是什么&#xff1f;二、来看一看NAND三、部署火灾检测 前言 前几天收到了雷龙NAND的芯片&#xff0c;一共两个芯片和一个转接板&#xff0c;我之前也没有使用过这款芯片&#xff0c;比较好奇&#xff0c;体验了一下&#xff0c;个人认为&#x…

嵌入式微处理器重点学习(三)

堆栈操作 R1=0x005 R3=0x004 SP=0x80014 STMFD sp!, {r1, r3} 指令STMFD sp!, {r1, r3}是一条ARM架构中的存储多个寄存器到内存的指令,这里用于将r1和r3寄存器的内容存储到栈上。STMFD(Store Multiple Full Descending)是一种全递减模式的多寄存器存储指令,它会先将栈指针…

three.js 基础01

1.场景创建 Scene() 2.常用形状集几何体「Geometry」[可设置长宽高等内容,如:new THREE.BoxGeometry(...)] 长方体 BoxGeometry圆柱体CylinderGeometry 球体SphereGeometry圆锥体ConeGeometry矩形平面 PlaneGeometry 圆面体CircleGeometry 3.常用材质「Materi…

linux 部署瑞数6实战(维普,药监局)sign第二部分

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx …

C/C++李峋同款跳动的爱心代码

一、写在前面 在编程的世界里&#xff0c;代码不仅仅是冷冰冰的命令&#xff0c;它也可以成为表达情感、传递浪漫的工具。今天&#xff0c;就让小编带着大家用C语言打造出李峋同款跳动的爱心吧&#xff01; 首先&#xff0c;我们需要知道C作为一种高级编程语言&#xff0c;拥…

宠物健康顾问系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;顾问管理&#xff0c;用户管理&#xff0c;健康知识管理&#xff0c;管理员管理&#xff0c;论坛管理&#xff0c;公告管理 顾问账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;顾…

头歌资源库(7)汉诺塔(循环)

一、 问题描述 二、算法思想 初始化三个柱子A、B、C&#xff0c;初始时所有的盘子都在柱子A上。对于从1到N&#xff08;N表示盘子的数量&#xff09;的每一个数字i&#xff0c;执行以下循环&#xff1a; a. 如果i是偶数&#xff0c;则将柱子B视为目标柱子&#xff0c;柱子C视为…

Python时间序列分析库

Sktime Welcome to sktime — sktime documentation 用于ML/AI和时间序列的统一API,用于模型构建、拟合、应用和验证支持各种学习任务,包括预测、时间序列分类、回归、聚类。复合模型构建,包括具有转换、集成、调整和精简功能的管道scikit学习式界面约定的交互式用户体验Pro…

【原创】springboot+mysql小区用水监控管理系统设计与实现

个人主页&#xff1a;程序猿小小杨 个人简介&#xff1a;从事开发多年&#xff0c;Java、Php、Python、前端开发均有涉猎 博客内容&#xff1a;Java项目实战、项目演示、技术分享 文末有作者名片&#xff0c;希望和大家一起共同进步&#xff0c;你只管努力&#xff0c;剩下的交…

AI 定位!GeoSpyAI上传一张图片分析具体位置 不可思议! ! !

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;常见AI大模型部署&#xff1a;点击&#xff01; &#x1f916;Ollama部署LLM专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年6月16日12点23分 &#x1f004;️文章质量&#xff1a;94分…

动态规划日常刷题

力扣70.爬楼梯 class Solution {public int climbStairs(int n) {return dfs(n);}//递归 //注意每次你可以爬 1 或 2 个台阶//如果最后一步是1 就先爬到n-1 把它缩小成0-n-1的范围//如果最后一步是2 就先爬到n-2 把它缩小成0-n-2的范围 private int dfs(int i){if(i < 1){r…

代码随想录算法训练营第五十九天|115.不同的子序列、 583. 两个字符串的删除操作、72. 编辑距离、编辑距离总结篇

代码随想录算法训练营第五十九天 115.不同的子序列 题目链接&#xff1a;115.不同的子序列 确定dp数组以及下标的含义&#xff1a;dp[i][j] &#xff1a;以下标i - 1为结尾的s&#xff0c;和以下标j - 1为结尾的t&#xff0c;s中t的个数dp[i][j]确定递推公式&#xff1a; s[…