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

news2024/11/14 11:18:20

重学 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;   // 用户ID
    String 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);
    }

    @Override
    public Boolean login(String uId, String uPwd) {
        logger.info("模拟淘宝用户登录 uId:{} uPwd:{}", uId, uPwd);
        return true;
    }

    @Override
    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", "4799.00");
        logger.info("模拟淘宝商品爬虫解析:{} | {} 元 {}", map.get("name"), map.get("price"), skuUrl);
        return map;
    }

    @Override
    public 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);
    }

    @Override
    public Boolean login(String uId, String uPwd) {
        logger.info("模拟当当用户登录 uId:{} uPwd:{}", uId, uPwd);
        return true;
    }

    @Override
    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", "4548.00");
        logger.info("模拟当当商品爬虫解析:{} | {} 元 {}", map.get("name"), map.get("price"), skuUrl);
        return map;
    }

    @Override
    public 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+E5rWL44CRLeS6rOS4nCJ9

Process finished with exit code 0

六、总结

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

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

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

相关文章

mysql和redis备份和恢复数据的笔记

一、mysql的备份及恢复方法&#xff1a; 1.完全备份与恢复 1.1物理备份与恢复 物理备份又叫冷备份&#xff0c;需停止数据库服务&#xff0c;适合线下服务器 备份数据流程&#xff1a; 第一步:制作备份文件 systemctl stop mysqld #创建存放备份文件的目录 mkdir /bakdir …

医疗行业携手用友BIP收入云,开启高效收入管理新时代

在医疗行业&#xff0c;收入管理是实现可持续发展的重要环节。随着医疗改革的深入和市场竞争的加剧&#xff0c;医疗机构需要寻找有效的收入管理破局方法。用友BIP收入云作为一款强大的收入管理工具&#xff0c;为医疗行业提供了有力的支持。 一、医疗行业收入管理破局方法 精细…

多视图变换矩阵与SLAM位姿估计中的地图点投影的几何约束

定义 Homography & projective transform M ( 3 4 ) [ f s x c ′ 0 a f y c ′ 0 0 1 ] [ 1 0 0 0 0 1 0 0 0 0 1 0 ] [ R 3 3 0 3 1 0 1 3 1 ] [ I 3 3 T 3 1 0 1 3 1 ] \underset{(3 \times 4)}{\mathbf{M}}\left[\begin{array}{ccc} f & s & x_c^{\pr…

前端已学习内容

一、HTMLCSS 1、黑马B站视频-27小时 地址&#xff1a;基础班导学-精讲与实战_哔哩哔哩_bilibili 说明&#xff1a;讲义已下载。两个小项目还没学没练。 2、菜鸟教程 地址&#xff1a;HTML 简介 | 菜鸟教程 二、JavaScript 1、菜鸟教程 网址&#xff1a;JavaScript 教程 …

【点击收藏】鸿蒙HarmonyOS实战开发—如何实现应用悬浮窗

前言 鸿蒙登场&#xff01;它的征途是万物互联 备受瞩目的华为HarmonyOS 2&#xff08;即鸿蒙系统&#xff09;正式发布。同时&#xff0c;华为发布了多款搭载鸿蒙系统的新产品&#xff0c;包括Mate 40系列新版本、Mate X2新版本、华为WATCH 3系列、华为MatePad Pro等手机、智能…

vue-editor设置字体font-family

背景&#xff1a;Vue项目中需要用到富文本编辑器&#xff0c;所以选择了vue-editor这个富文本编辑器&#xff0c;发现字体font-family只有三种Sans Serif、Serif、MonoSpace可以选择&#xff0c;满足不了产品的需求&#xff0c;所以用想要定义成常用字体&#xff0c;主要是需要…

AGI时代的奠基石:Agent+算力+大模型是构建AI未来的三驾马车吗

★AI Agent&#xff1b;人工智能体&#xff0c;RPA&#xff1b;大语言模型&#xff1b;prompt&#xff1b;Copilot&#xff1b;AGI&#xff1b;ChatGPT&#xff1b;LLM&#xff1b;AIGC&#xff1b;CoT&#xff1b;Cortex&#xff1b;Genius&#xff1b;MetaGPT&#xff1b;大模…

借助ChatGPT撰写学术论文,如何设定有效的角色提示词指

大家好&#xff0c;感谢关注。这个给大家提供关于论文写作方面专业的讲解&#xff0c;以及借助ChatGPT等AI工具如何有效辅助的攻略技巧。有兴趣的朋友可以添加我&#xff08;yida985&#xff09;交流学术写作或ChatGPT等AI领域相关问题&#xff0c;多多交流&#xff0c;相互成就…

段页式管理

缝合怪&#xff01;&#xff01;&#xff01; 分页、分段的对比 分段分页段页式管理 先将进程按逻辑模块分段&#xff0c;再将各段分页 段页式管理的逻辑地址结构 段号页号页内偏移量 段号的位数&#xff1a;决定了每个进程最多可以分为几个段。 页号的位数&#xff1a;决定…

马斯克怒了,禁止员工使用苹果设备,抨击库克出卖数据给OpenA

昨晚&#xff0c;苹果发布会正式宣布了一系列重磅AI升级&#xff0c;甚至创造了一个新的概念——苹果智能&#xff08;Apple Intelligence&#xff09;。 这次升级在操作系统的交互层面上进行了智能化改进&#xff0c;使得更多自然语音和语言理解的控制成为可能&#xff0c;将…

常见数据编码方式

数据编码方式&#xff1a; 二进制数字信息在传输过程中可以采用不同的代码&#xff0c;各种代码的抗噪声特征和定时功能各不相同&#xff0c;实现费用也不一样。下面介绍几种常用的编码方式。 1、单极性码 在这种编码方案中&#xff0c;只用正的&#xff08;或负的&#xff09;…

服务器如何远程桌面连接不上,服务器远程桌面连接不上解决办法

服务器远程桌面连接不上&#xff0c;是IT运维中常见的挑战之一。针对这一问题&#xff0c;专业的解决方法通常涉及以下几个方面的排查与操作&#xff1a; 首先&#xff0c;我们需要检查网络连接是否正常。远程桌面连接依赖于稳定的网络连接&#xff0c;因此&#xff0c;确认服务…

第十九节:暴力递归到动态规划

一 动画规划的概念 优化出现重复解的递归 一旦写出递归来&#xff0c;改动态规划就很快 尝试策略和状态转移方程是一码事 学会尝试是攻克动态规划最本质的能力 如果你发现你有重复调用的过程&#xff0c;动态规划在算过一次之后把答案记下来&#xff0c;下回在越到重复调用过程…

Java四舍五入保留小数

这里介绍两种方法&#xff1a; package Book.jj.hh;import java.text.DecimalFormat; //使用DecimalFormat类 public class Demo1 {public static void main(String[] args) {double num 123.52631;DecimalFormat a new DecimalFormat("#.00"); //小数点后有几个0…

UE4 RPC进行网络同步

说明 基于UE本身提供的RPC同步机制 RPC远程过程调用允许客户端或服务器通过网络连接相互发送消息&#xff1a; 使用时需要注意&#xff1a; 1、必须从 Actor 上调用 2、Actor 必须被复制&#xff0c;注意勾选BP中Replicates&#xff0c;或使变量bReplicates true 3、注意如…

揭秘独孤信印章:多面性与历史地位的双重传奇

2024高考已经结束&#xff0c;小编回顾前几年高考试卷时发现在2019年全国高考II卷中&#xff0c;一枚古老的印章被做成了一道数学题。这枚印章不仅因其独特的多面体设计而引人注目&#xff0c;更因为其背后所代表的历史人物——独孤信&#xff0c;而成为了热门的话题。那么&…

pip切换至国内镜像超简单方法

新配置的python环境&#xff0c;pip安装包超时 这里给出最简单配置国内镜像的方法 这里将服务器地址切换为国内清华镜像&#xff0c;具体执行的命令如下&#xff1a; pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple 执行完&#xff0c;看到上面提…

【C++ 类和对象】初始化列表

文章目录 1. 构造函数体赋值2. 初始化列表&#x1f50d; 1. 构造函数体赋值 &#x1f34e;① 在创建对象时&#xff0c;编译器通过调用构造函数&#xff0c;给对象中各个成员变量一个合适的初始值。 class Date { public:// 构造函数 Date(int year, int month, int day) {_y…

面试题:如何避免索引失效?

(1) 范围条件查询 (2) 不要在索引上使用函数运算, 否则索引也会失效. 比如在索引上使用切割函数, 就会使索引失效. (3) 字符串不加引号, 造成索引失效. (4) 尽量使用索引覆盖, 避免 select *, 这样能提高查询效率. 如果索引列完全包含查询列, 那么查询的时候把要查的列写出来…

一文教你如何实现并发请求的失败自动重试及重试次数限制

需求 在并发接口请求的时候&#xff0c;能够自动对失败的请求进行重发尝试&#xff08;超过指定重试次数则不再重试&#xff09;,并将最终的结果返回&#xff08;包含每个请求是否成功、返回结果&#xff09; 核心思路 代码实现 使用案例 为了演示我们代码的最终实现效果&a…