電商系統(tǒng)設(shè)計(jì)模式實(shí)戰(zhàn)
點(diǎn)擊下方“IT牧場(chǎng)”,選擇“設(shè)為星標(biāo)”

1 代理模式
案例:根據(jù)文件類型,將文件存儲(chǔ)到不同服務(wù)
代理模式:給一個(gè)對(duì)象創(chuàng)建一個(gè)代理對(duì)象,通過(guò)代理對(duì)象可以使用該對(duì)象的功能。
CGLib和JDK是代理模式實(shí)現(xiàn)的技術(shù)方案。
1.1 文件服務(wù)應(yīng)用
代理模式的應(yīng)用場(chǎng)景除了代碼級(jí)別,還可以將代理模式遷移到應(yīng)用以及架構(gòu)級(jí)別,如下圖文件上傳代理服務(wù),針對(duì)一些圖片小文件,我們可以直接把文件存儲(chǔ)到FastDFS服務(wù),針對(duì)大文件,例如商品視頻介紹,我們可以把它存儲(chǔ)到第三方OSS。
用戶通過(guò)文件上傳代理服務(wù)可以間接訪問(wèn)OSS和本地FastDFS,這種分布式海量文件管理解決方案,這里不僅在代碼層面充分運(yùn)用了代理模式,在架構(gòu)層面也充分運(yùn)用了代理模式。

1.2 分布式文件代理服務(wù)器實(shí)現(xiàn)
1.2.1 實(shí)現(xiàn)分析
基于代理模式,我們實(shí)現(xiàn)文件上傳分別路由到 aliyunOSS 和 FastDFS ,用例圖如下:

講解:
1、FileUpload抽象接口,定義了文件上傳方法,分別給它寫了2種實(shí)現(xiàn)。
2、AliyunOSSFileUpload是將文件上傳到aliyunOSS,主要上傳mp4和avi的視頻大文件。
3、FastdfsFileUpoad是將文件上傳到FastDFS,主要上傳png/jpg等圖片小文件。
4、FileUploadProxy是代理對(duì)象,供用戶訪問(wèn),調(diào)用了FileUpload的文件上傳方法,為用戶提供不同文件上傳調(diào)用。
5、FileController是控制器,用于接收用戶提交的文件,并調(diào)用代理FileUploadProxy實(shí)現(xiàn)文件上傳。
1.2.2 代碼實(shí)現(xiàn)
bootstrap.yml配置:


FileUpload接口定義:

AliyunOSSFileUpload實(shí)現(xiàn):


FastdfsFileUpoad實(shí)現(xiàn):


FileUploadProxy代理實(shí)現(xiàn):


FileController控制器實(shí)現(xiàn)

2 享元模式
定義:運(yùn)用共享技術(shù)來(lái)有效地支持大量細(xì)粒度對(duì)象的復(fù)用。它通過(guò)共享已經(jīng)存在的對(duì)象來(lái)大幅度減少需要?jiǎng)?chuàng)建的對(duì)象數(shù)量、避免大量相似類的開銷,從而提高系統(tǒng)資源的利用率。
享元模式和單利的區(qū)別:
單例是對(duì)象只能自己創(chuàng)建自己,整個(gè)應(yīng)用中只有1個(gè)對(duì)象
享元模式根據(jù)需要共享,不限制被誰(shuí)創(chuàng)建(有可能有多個(gè)對(duì)象實(shí)例)
優(yōu)點(diǎn):
特定環(huán)境下,相同對(duì)象只要保存一份,這降低了系統(tǒng)中對(duì)象的數(shù)量,從而降低了系統(tǒng)中細(xì)粒度對(duì)象給內(nèi)存帶來(lái)的壓力。
缺點(diǎn):
為了使對(duì)象可以共享,需要將一些不能共享的狀態(tài)外部化,這將增加程序的復(fù)雜性
2.1 享元模式實(shí)戰(zhàn)
案例:用戶下單,會(huì)話共享
2.1.1 會(huì)話跟蹤分析
會(huì)話跟蹤,如果是傳統(tǒng)項(xiàng)目用Session或者是Cookie,全項(xiàng)目通用,但在微服務(wù)項(xiàng)目中,不用Session也不用Cookie,所以想要在微服務(wù)項(xiàng)目中實(shí)現(xiàn)會(huì)話跟蹤,是有一定難度的。
當(dāng)前微服務(wù)項(xiàng)目中,身份識(shí)別的主流方法是前端將用戶令牌存儲(chǔ)到請(qǐng)求頭中,每次請(qǐng)求將請(qǐng)求頭中的令牌攜帶到后臺(tái),后臺(tái)每次從請(qǐng)求頭中獲取令牌來(lái)識(shí)別用戶身份。
我們?cè)陧?xiàng)目操作過(guò)程中,很多地方都會(huì)用到用戶身份信息,比如下訂單的時(shí)候,要知道當(dāng)前訂單屬于哪個(gè)用戶,記錄下單關(guān)鍵日志的時(shí)候,需要記錄用戶操作的信息以及用戶信息,關(guān)鍵日志記錄我們一般用AOP進(jìn)行攔截操作,此時(shí)沒(méi)法直接把用戶身份信息傳給AOP。這個(gè)時(shí)候我們可以利用享元模式實(shí)現(xiàn)用戶會(huì)話信息共享操作。操作流程如下圖:

2.1.2 會(huì)話共享案例實(shí)現(xiàn)
基于上面的分析,我們采用享元模式實(shí)現(xiàn)用戶會(huì)話共享操作,要解決如下幾個(gè)問(wèn)題:

定義共享組件:LogComponent
LogComponent 里面定義了每個(gè)線程中不變的用戶身份信息 username 、 role 、 sex ,其他的是可能存在變化的數(shù)據(jù),例如用于做日志記錄的 methodName 、 message 。

享元組件邏輯操作對(duì)象:SupplementSource
SupplementSource 該對(duì)象主要用于給當(dāng)前線程填充共享數(shù)據(jù),以及變更訪問(wèn)方法和訪問(wèn)信息等信息的邏輯操作,代碼如下:

多線程安全控制:ThreadUserLog
每個(gè)線程請(qǐng)求的時(shí)候,我們需要保障會(huì)話安全,比如A線程訪問(wèn)和B線程訪問(wèn),他們的用戶會(huì)話身份不能因?yàn)椴l(fā)原因而發(fā)生混亂。這里我們可以采用ThreadLocal來(lái)實(shí)現(xiàn)。我們創(chuàng)建一個(gè) ThreadUserLog 對(duì)象,并在該對(duì)象中創(chuàng)建ThreadLocal


線程會(huì)話初始化:AuthorizationInterceptor
AuthorizationInterceptor 攔截器的作用是用于初始化用戶訪問(wèn)的時(shí)候用戶的身份信息,并將身份信息存儲(chǔ)到ThreadUserLog 的 ThreadLocal 中,在用戶訪問(wèn)方法結(jié)束,銷毀 ThreadUserLog 的 ThreadLocal 中會(huì)話,代碼如下:


創(chuàng)建 MvcConfig 來(lái)配置攔截器 AuthorizationInterceptor ,代碼如下:
共享信息使用:
①AOP記錄日志:創(chuàng)建AOP切面類 LogAspect 用于記錄日志,代碼如下:

②添加訂單獲取用戶信息:在添加訂單方法 OrderServiceImpl.add(Order order) 中,從ThreadUserLog中獲取用戶會(huì)話,并填充給Order,代碼如下

添加訂單,日志輸出可以看到調(diào)用添加訂單和修改庫(kù)存時(shí),都記錄了日志,并且獲取了用戶會(huì)話,效果如下:

加的訂單數(shù)據(jù)庫(kù)數(shù)據(jù)中也擁有用戶信息,效果如下:

3 裝飾著模式
定義:動(dòng)態(tài)的向一個(gè)現(xiàn)有的對(duì)象添加新的功能,同時(shí)又不改變其結(jié)構(gòu)。它屬于結(jié)構(gòu)型模式。
優(yōu)點(diǎn):裝飾類和被裝飾類可以獨(dú)立發(fā)展,不會(huì)相互耦合,裝飾模式是繼承的一個(gè)替代模式,裝飾模式可以動(dòng)態(tài)擴(kuò)展一個(gè)實(shí)現(xiàn)類的功能
缺點(diǎn):多層裝飾比較復(fù)雜。
3.1 裝飾者模式實(shí)戰(zhàn)
案例:結(jié)算價(jià)格計(jì)算,根據(jù)不同價(jià)格嵌套運(yùn)算
在訂單提交的時(shí)候,訂單價(jià)格和結(jié)算價(jià)格其實(shí)是兩碼事,訂單價(jià)格是當(dāng)前商品成交價(jià)格,而結(jié)算價(jià)格是用戶最終需要支付的金額,最終支付的金額并不是一成不變,它也并不是商品成交價(jià)格,能改變結(jié)算價(jià)格的因素很多,比如滿100減10元,VIP用戶再減5塊。訂單結(jié)算金額計(jì)算我們就可以采用裝飾者模式。

3.1.2 裝飾者模式價(jià)格運(yùn)算實(shí)現(xiàn)
實(shí)現(xiàn)思路分析:

基礎(chǔ)接口:創(chuàng)建接口 MoneySum ,該接口只用于定義計(jì)算訂單金額的方法。

訂單金額計(jì)算類:創(chuàng)建類 OrderPayMoneyOperation 實(shí)現(xiàn)訂單金額的計(jì)算。

裝飾者類:創(chuàng)建裝飾者類 DecoratorMoneySum 供其他類擴(kuò)展。
滿100減10元價(jià)格計(jì)算:創(chuàng)建類 FullMoneySum 擴(kuò)展裝飾者類,實(shí)現(xiàn)滿減價(jià)格計(jì)算。
VIP優(yōu)惠10元價(jià)格計(jì)算:創(chuàng)建類 VipMoneySum ,實(shí)現(xiàn)VIP優(yōu)惠計(jì)算。

支付金額計(jì)算:修改 OrderServiceImpl 的 add() 方法,添加訂單金額以及訂單支付金額的計(jì)算功能,代碼如下:

測(cè)試效果:
測(cè)試數(shù)據(jù)中,我們選擇購(gòu)買1件商品,當(dāng)前登錄用戶為王五,擁有5個(gè)金幣,當(dāng)前購(gòu)買的商品id=1,商品單價(jià)是150元,滿減100,VIP優(yōu)惠5元,最終支付135元。

測(cè)試生成的訂單如下:

不僅如此,我們可以隨時(shí)撤掉滿減和Vip優(yōu)惠功能。
4 策略模式
定義:策略模式是對(duì)算法的包裝,把使用算法的責(zé)任和算法本身分隔開,委派給不同的對(duì)象管理。策略模式通常把一系列的算法包裝到一系列的策略類里面,作為一個(gè)抽象策略類的子類。
簡(jiǎn)單來(lái)說(shuō)就是就定義一個(gè)策略接口,子類策略去實(shí)現(xiàn)該接口去定義不同的策略。然后定義一個(gè)環(huán)境(Context,也就是需要用到策略的對(duì)象)類,以策略接口作為成員變量,根據(jù)環(huán)境來(lái)使用具體的策略。
優(yōu)點(diǎn):

缺點(diǎn):

4.1 策略模式實(shí)戰(zhàn)
案例:結(jié)算價(jià)格計(jì)算,根據(jù)Vip不同等級(jí)進(jìn)行運(yùn)算
4.1.1 不同VIP優(yōu)惠價(jià)格分析

用戶在購(gòu)買商品的時(shí)候,很多時(shí)候會(huì)根據(jù)Vip等級(jí)打不同折扣,尤其是在線商城中體現(xiàn)的淋漓盡致。我們這里也基于真實(shí)電商案例來(lái)實(shí)現(xiàn)VIP等級(jí)價(jià)格制:

4.1.2 代碼實(shí)現(xiàn)
定義策略接口:Strategy

定義Vip0策略:StrategyVipOne

定義Vip1策略:?StrategyVipTwo

定義Vip2策略:StrategyVipThree

定義Vip3策略:StrategyVipFour

定義策略工廠:StrategyFactory

等級(jí)策略配置:修改application.yml,將如下策略配置進(jìn)去

等級(jí)控制:修改 UserHandler 添加等級(jí)屬性

修改 UserHandlerShare 定義等級(jí),代碼如下:

裝飾者模式中修改 VipMoneySum 的價(jià)格運(yùn)算,代碼如下:

測(cè)試:

5 工廠模式
案例:收銀案例,根據(jù)不同支付方式,選擇不同支付渠道
定義:定義一個(gè)創(chuàng)建產(chǎn)品對(duì)象的工廠接口,將產(chǎn)品對(duì)象的實(shí)際創(chuàng)建工作推遲到具體子工廠類當(dāng)中。這滿足創(chuàng)建型模式中所要求的“創(chuàng)建與使用相分離”的特點(diǎn)。
5.1 工廠模式實(shí)戰(zhàn)
5.1.1 支付渠道選中分析
用戶每次下單完成后,需要支付訂單,支付訂單會(huì)根據(jù)自身情況選擇不同支付方式,后臺(tái)服務(wù)會(huì)根據(jù)用戶選中不同創(chuàng)建不同支付渠道的實(shí)例,這里創(chuàng)建支付渠道的實(shí)例可以采用工廠方法模式。

5.1.2 代碼實(shí)現(xiàn)
工廠方法在SpringBoot中如果在用工廠的同時(shí)又出現(xiàn)了new,那絕對(duì)是一個(gè)敗筆。在SpringBoot中,幾乎所有對(duì)象
都可以直接交給Spring容器管理,它天然已經(jīng)是一個(gè)工廠對(duì)象,因此在SpringBoot項(xiàng)目中用工廠模式,再頻繁new對(duì)象反而不妥。那么工廠模式究竟怎么用在SpringBoot項(xiàng)目的支付場(chǎng)景呢?其實(shí)很簡(jiǎn)單,如果我們要選擇一個(gè)支付渠道,而項(xiàng)目中有100種支付渠道,那這個(gè)時(shí)候無(wú)疑要寫100個(gè) @Autowired 注入100個(gè)支付渠道,并且需要做100種判斷,這個(gè)時(shí)候我們可以用工廠模式取代我們判斷,直接根據(jù)我們配置的映射關(guān)系從Spring容器中拿到對(duì)應(yīng)支付渠道的實(shí)例,代碼量將大大減少,這塊是使用工廠的另一種妙用
支付接口:?PayChannel 定義支付行為。

微信支付實(shí)現(xiàn):WeixinPay 實(shí)現(xiàn)微信支付操作,這里只模擬。

支付寶支付實(shí)現(xiàn):?AliPay 實(shí)現(xiàn)支付寶支付,這里只模擬。

支付渠道映射配置:在 application.yml 中配置支付渠道映射,每次從前端傳入支付ID即可從配置中獲取支付渠道對(duì)應(yīng)Spring容器中實(shí)例的id。

支付渠道獲取工廠創(chuàng)建:創(chuàng)建 PayFactory 用于獲取支付渠道的實(shí)例,我們這里通過(guò)映射的key獲取Spring容器中實(shí)例的id值,然后從Spring容器中根據(jù)id獲取對(duì)應(yīng)實(shí)例,因此該工廠需要實(shí)現(xiàn)接口 ApplicationContextAware 來(lái)獲取容器。

支付渠道調(diào)用實(shí)現(xiàn):修改 PayServiceImpl 的 pay 方法,實(shí)現(xiàn)支付,代碼如下:

測(cè)試:當(dāng)我們選中支付渠道為1(微信支付)或者2(支付寶支付)的時(shí)候,都能爭(zhēng)取獲取對(duì)應(yīng)的渠道實(shí)例。

6 狀態(tài)模式
案例:訂單不同狀態(tài),執(zhí)行不同操作
定義:對(duì)有狀態(tài)的對(duì)象,把復(fù)雜的“判斷邏輯”提取到不同的狀態(tài)對(duì)象中,允許狀態(tài)對(duì)象在其內(nèi)部狀態(tài)發(fā)生改變時(shí)改變其行為。
優(yōu)點(diǎn)

缺點(diǎn)

6.1 狀態(tài)模式實(shí)戰(zhàn)
6.1.1 狀態(tài)模式案例分析
在電商案例中,訂單狀態(tài)每次發(fā)生變更,都要執(zhí)行不同的操作,這里正好可以使用狀態(tài)模式。當(dāng)訂單完成支付的時(shí)候,我們需要立即通知商家發(fā)貨,當(dāng)訂單執(zhí)行取消的時(shí)候,我們需要執(zhí)行庫(kù)存回滾,如果訂單已支付,還需要執(zhí)行退款操作,無(wú)論是通知商家發(fā)貨還是執(zhí)行庫(kù)存回滾,都是有訂單狀態(tài)決定,因此這里可以使用狀態(tài)模式來(lái)實(shí)現(xiàn)
我們可以先定義狀態(tài)接口 State ,給狀態(tài)接口實(shí)現(xiàn)兩個(gè)不同的行為,分別是發(fā)貨和回滾庫(kù)存并退款,把該狀態(tài)對(duì)象添加到訂單內(nèi)部作為成員屬性,當(dāng)訂單的 state 狀態(tài)改變時(shí),觸發(fā)執(zhí)行不同的狀態(tài)行為動(dòng)作。

5.1.2 案例實(shí)現(xiàn)
狀態(tài)接口定義:State 接口,用于定義更新狀態(tài)對(duì)象,同時(shí)執(zhí)行相關(guān)的行為。

發(fā)通知消息行為定義:SendMsgBehavior 用于實(shí)現(xiàn)給商家發(fā)送消息通知發(fā)貨,這里模擬發(fā)送消息的行為。

庫(kù)存回滾并退款:創(chuàng)建 ResetStoreBehavior ,用于實(shí)現(xiàn)訂單庫(kù)存回滾,并給用戶退款操作,這里退款模擬相關(guān)行
為。

測(cè)試:
支付訂單的時(shí)候,如果支付成功,我們調(diào)用 State 變更對(duì)應(yīng)的狀態(tài)行為,并執(zhí)行相關(guān)行為,代碼如下:

測(cè)試結(jié)果如下:

干貨分享
最近將個(gè)人學(xué)習(xí)筆記整理成冊(cè),使用PDF分享。關(guān)注我,回復(fù)如下代碼,即可獲得百度盤地址,無(wú)套路領(lǐng)取!
?001:《Java并發(fā)與高并發(fā)解決方案》學(xué)習(xí)筆記;?002:《深入JVM內(nèi)核——原理、診斷與優(yōu)化》學(xué)習(xí)筆記;?003:《Java面試寶典》?004:《Docker開源書》?005:《Kubernetes開源書》?006:《DDD速成(領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)速成)》?007:全部?008:加技術(shù)群討論
加個(gè)關(guān)注不迷路
喜歡就點(diǎn)個(gè)"在看"唄^_^
