天天看點

重學 Java 設計模式:實戰模版模式「模拟爬蟲各類電商商品,生成營銷推廣海報場景」

重學 Java 設計模式:實戰模版模式「模拟爬蟲各類電商商品,生成營銷推廣海報場景」

作者:小傅哥

部落格:https://bugstack.cn -

原創系列專題文章

沉澱、分享、成長,讓自己和他人都能有所收獲!😄

一、前言

黎明前的堅守,的住嗎?

有人舉過這樣一個例子,先給你張北大的錄取通知書,但要求你每天5點起床,12點睡覺😪,刻苦學習,勤奮上進。隻要你堅持三年,這張通知書就有效。如果是你,你能堅持嗎?其實對于這個例子很難在我們的人生中出現,因為它目标明确,有準确的行軍路線。就像你是土豪家庭,家裡給你安排的明明白白一樣,隻要你按照這個方式走就不會有問題。可大多數時候我們并沒有這樣的路線,甚至不知道多久到達自己的黎明。但!誰又不渴望見到黎明呢,堅持吧!

不要輕易被洗腦

鍵盤俠⌨

網絡噴壺

,幾乎當你努力堅持一件事的時候,在這條路上會遇到形形色色的人和事。有時候接收建議完善自己是有必要的,但不能放棄自己的初心和底線,有時候隻堅持自己也是難能可貴的。

子路之勇,子貢之辯,冉有之智,此三子者,皆天下之所謂難能而可貴者也

。陽光和努力是這個世界最溫暖的東西,加油堅持好自己的選的路。

有時還好堅持了

當你為自己的一個決定而感到萬分開心😄時,是不是也非常感謝自己還好堅持了。堅持、努力、終身學習,似乎在程式員這個行業是離不開的,當你意願于把這當做一份可以努力的愛好時,你就會願意為此而努力。而我們很難說隻在機會要來時準備,而是一直努力等待機會。也就是很多人說的别人抓住機會是因為一直在準備着。

二、開發環境

  1. JDK 1.8
  2. Idea + Maven
  3. 涉及工程三個,可以通過關注公衆号:

    bugstack蟲洞棧

    ,回複

    源碼下載下傳

    擷取(打開擷取的連結,找到序号18)
工程 描述
itstack-demo-design-21-00 場景模拟工程;模拟爬蟲商品生成海報場景

三、模版模式介紹

重學 Java 設計模式:實戰模版模式「模拟爬蟲各類電商商品,生成營銷推廣海報場景」

模闆模式的核心設計思路是通過在,抽象類中定義抽象方法的執行順序,并将抽象方法設定為隻有子類實作,但不設計

獨立通路

的方法。簡單說也就是把你安排的明明白白的。

重學 Java 設計模式:實戰模版模式「模拟爬蟲各類電商商品,生成營銷推廣海報場景」

就像西遊記的99八十一難,基本每一關都是;師傅被擄走、打妖怪、妖怪被收走,具體什麼妖怪你自己定義,怎麼打你想辦法,最後收走還是弄死看你本事,我隻定義執行順序和基本政策,具體的每一難由觀音來安排。

四、案例場景模拟

重學 Java 設計模式:實戰模版模式「模拟爬蟲各類電商商品,生成營銷推廣海報場景」

在本案例中我們模拟爬蟲各類電商商品,生成營銷推廣海報場景

關于模版模式的核心點在于由抽象類定義抽象方法執行政策,也就是說父類規定了好一系列的執行标準,這些标準的串聯成一整套業務流程。

在這個場景中我們模拟爬蟲爬取各類商家的商品資訊,生成推廣海報(

海報中含帶個人的邀請碼

)賺取商品返利。聲明,這裡是模拟爬取,并沒有真的爬取

而整個的爬取過程分為;模拟登入、爬取資訊、生成海報,這三個步驟,另外;

  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
           

模版模式模型結構

重學 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 JDNetMall

    new TaoBaoNetMall

    new 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
           

六、總結

  • 通過上面的實作可以看到

    模版模式

    在定義統一結構也就是執行标準上非常友善,也就很好的控制了後續的實作者不用關心調用邏輯,按照統一方式執行。那麼類的繼承者隻需要關心具體的業務邏輯實作即可。
  • 另外模版模式也是為了解決子類通用方法,放到父類中設計的優化。讓每一個子類隻做子類需要完成的内容,而不需要關心其他邏輯。這樣提取公用代碼,行為由父類管理,擴充可變部分,也就非常有利于開發拓展和疊代。
  • 但每一種設計模式都有自己的特定場景,如果超過場景外的建設就需要額外考慮🤔其他模式的運用。而不是非要生搬硬套,否則自己不清楚為什麼這麼做,也很難讓後續者繼續維護代碼。而想要活學活用就需要多加練習,有實踐的經曆。

七、推薦閱讀

  • 1. 重學 Java 設計模式:實戰工廠方法模式「多種類型商品不同接口,統一發獎服務搭建場景」

  • 2. 重學 Java 設計模式:實戰原型模式「上機考試多套試,每人題目和答案亂序排列場景」

  • 3. 重學 Java 設計模式:實戰橋接模式「多支付管道(微信、支付寶)與多支付模式(刷臉、指紋)場景」

  • 4. 重學 Java 設計模式:實戰組合模式「營銷差異化人群發券,決策樹引擎搭建場景」

  • 5. 重學 Java 設計模式:實戰外觀模式「基于SpringBoot開發門面模式中間件,統一控制接口白名單場景」

  • 6. 重學 Java 設計模式:實戰享元模式「基于Redis秒殺,提供活動與庫存資訊查詢場景」

  • 7. 重學 Java 設計模式:實戰備忘錄模式「模拟網際網路系統上線過程中,配置檔案復原場景」

公衆号:bugstack蟲洞棧 | 作者小傅哥多年從事一線網際網路 Java 開發的學習曆程技術彙總,旨在為大家提供一個清晰詳細的學習教程,側重點更傾向編寫Java核心内容。如果能為您提供幫助,請給予支援(關注、點贊、分享)!