重學 Java 設計模式:實戰模版模式「模擬爬蟲各類電商商品,生成營銷推廣海報場景」
作者:小傅哥
博客: https://bugstack.cn - 原創系列專題文章
沉澱、分享、成長,讓自己和他人都能有所收穫!:smile:
一、前言
黎明前的堅守,的住嗎?
有人舉過這樣一個例子,先給你張北大的錄取通知書,但要求你每天5點起牀,12點睡覺:sleepy:,刻苦學習,勤奮上進。只要你堅持三年,這張通知書就有效。如果是你,你能堅持嗎?其實對於這個例子很難在我們的人生中出現,因爲它目標明確,有準確的行軍路線。就像你是土豪家庭,家裏給你安排的明明白白一樣,只要你按照這個方式走就不會有問題。可大多數時候我們並沒有這樣的路線,甚至不知道多久到達自己的黎明。但!誰又不渴望見到黎明呢,堅持吧!
不要輕易被洗腦
鍵盤俠⌨
、 網絡噴壺
,幾乎當你努力堅持一件事的時候,在這條路上會遇到形形色色的人和事。有時候接收建議完善自己是有必要的,但不能放棄自己的初心和底線,有時候只堅持自己也是難能可貴的。 子路之勇,子貢之辯,冉有之智,此三子者,皆天下之所謂難能而可貴者也
。陽光和努力是這個世界最溫暖的東西,加油堅持好自己的選的路。
有時還好堅持了
當你爲自己的一個決定而感到萬分開心:smile:時,是不是也非常感謝自己還好堅持了。堅持、努力、終身學習,似乎在程序員這個行業是離不開的,當你意願於把這當做一份可以努力的愛好時,你就會願意爲此而努力。而我們很難說只在機會要來時準備,而是一直努力等待機會。也就是很多人說的別人抓住機會是因爲一直在準備着。
二、開發環境
- JDK 1.8
- Idea + Maven
- 涉及工程三個,可以通過關注 公衆號 :
bugstack蟲洞棧
,回覆源碼下載
獲取(打開獲取的鏈接,找到序號18)
工程 | 描述 |
---|---|
itstack-demo-design-21-00 | 場景模擬工程;模擬爬蟲商品生成海報場景 |
三、模版模式介紹
模板模式的核心設計思路是通過在,抽象類中定義抽象方法的執行順序,並將抽象方法設定爲只有子類實現,但不設計 獨立訪問
的方法。簡單說也就是把你安排的明明白白的。
就像西遊記的99八十一難,基本每一關都是;師傅被擄走、打妖怪、妖怪被收走,具體什麼妖怪你自己定義,怎麼打你想辦法,最後收走還是弄死看你本事,我只定義執行順序和基本策略,具體的每一難由觀音來安排。
四、案例場景模擬
在本案例中我們模擬爬蟲各類電商商品,生成營銷推廣海報場景
關於模版模式的核心點在於由抽象類定義抽象方法執行策略,也就是說父類規定了好一系列的執行標準,這些標準的串聯成一整套業務流程。
在這個場景中我們模擬爬蟲爬取各類商家的商品信息,生成推廣海報( 海報中含帶個人的邀請碼
)賺取商品返利。 聲明,這裏是模擬爬取,並沒有真的爬取
而整個的爬取過程分爲;模擬登錄、爬取信息、生成海報,這三個步驟,另外;
- 因爲有些商品只有登錄後纔可以爬取,並且登錄可以看到一些特定的價格這與未登錄用戶看到的價格不同。
- 不同的電商網站爬取方式不同,解析方式也不同,因此可以作爲每一個實現類中的特定實現。
- 生成海報的步驟基本一樣,但會有特定的商品來源標識。所以這樣三個步驟可以使用模版模式來設定,並有具體的場景做子類實現。
五、模版模式搭建工程
模版模式的業務場景可能在平時的開發中並不是很多,主要因爲這個設計模式會在抽象類中定義邏輯行爲的執行順序。一般情況下,我們用的抽象類定義的邏輯行爲都比較輕量級或者沒有,只是提供一些基本方法公共調用和實現。
但如果遇到適合的場景使用這樣的設計模式也是非常方便的,因爲他可以控制整套邏輯的執行順序和統一的輸入、輸出,而對於實現方只需要關心好自己的業務邏輯即可。
而在我們這個場景中,只需要記住這三步的實現即可; 模擬登錄
、 爬取信息
、 生成海報
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 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
六、總結
模版模式