14

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

 3 years ago
source link: http://www.cnblogs.com/xiaofuge/p/13264924.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
3aEZBrI.png!web

作者:小傅哥

博客: https://bugstack.cn - 原创系列专题文章

沉淀、分享、成长,让自己和他人都能有所收获!:smile:

一、前言

黎明前的坚守,的住吗?

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

不要轻易被洗脑

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

有时还好坚持了

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

二、开发环境

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

三、模版模式介绍

uiqY3ie.jpg!web

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

qqIfeuv.jpg!web

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

四、案例场景模拟

eIf6jyv.jpg!web

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

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

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

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

  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

模版模式模型结构

YfInu2F.jpg!web

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

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 11】Apple 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

六、总结

模版模式

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK