摘要:模式定義策略模式的定義策略模式定義了算法族,分別封裝起來,讓它們之間可以互相替換,此模式讓算法的變化獨(dú)立于使用算法的客戶。模板方法模式定義模板方法模式在一個(gè)方法中定義一個(gè)算法骨架,而將一些步驟延遲到子類中。
最近在給公司的商城做第三方支付的對(duì)接,看了一下以前的微信支付,感覺結(jié)合了一下之前看的設(shè)計(jì)模式,想試試能不能在上面用上。一番研究后,感覺也是可以,就是可能有點(diǎn)牛刀小試。
模式定義策略模式的定義
策略模式定義了算法族,分別封裝起來,讓它們之間可以互相替換,此模式讓算法的變化獨(dú)立于使用算法的客戶。
模板方法模式定義
模板方法模式在一個(gè)方法中定義一個(gè)算法骨架,而將一些步驟延遲到子類中。模板方法使得子類可以在不改變算法結(jié)構(gòu)的情況下,重新定義算法中的某些步驟。
1、 場景描述
微信支付有預(yù)下單、退款、訂單查詢等等接口,看了下第三方支付,同樣也是類似的三板斧。很容易,我們會(huì)想到以下這個(gè)類圖:
圖中可以看到WxPay和SandPay都繼承了Pay,他們有同樣的行為:下單、退款、訂單查詢,但是,我們可以知道他們的實(shí)現(xiàn)肯定是不一樣的,這樣我們都必須覆蓋父類的方法,來處理不一樣支付的細(xì)節(jié),這樣的時(shí)候,代碼就會(huì)顯得冗余,每個(gè)子類都需要覆蓋父類的實(shí)現(xiàn),如何讓代碼更加統(tǒng)一呢?
2、 問題分析
這個(gè)時(shí)候,我們需要的是將行為獨(dú)立出來,讓其封裝在特定的行為類里,這樣,我們就能“指定”行為到支付的實(shí)例。比如說,我們想要產(chǎn)生一個(gè)新的第三方支付實(shí)例,我們可以動(dòng)態(tài)的讓其實(shí)現(xiàn)微信支付的下單操作(當(dāng)然這是不合理)。
這時(shí),我們用到了一個(gè)很重要的設(shè)計(jì)原則:
針對(duì)接口編程,而不是針對(duì)實(shí)現(xiàn)編程
我們用接口代表每個(gè)行為,比如說,OrderBehavior和RefundBehavior,行為的每個(gè)實(shí)現(xiàn)都講實(shí)現(xiàn)其中一個(gè)接口。支付類不會(huì)實(shí)現(xiàn)下單和退款的接口,而是有其他類專門實(shí)現(xiàn)。我們稱這種類叫“行為”類。和以前做法不一樣的地方在于,以前的做法是:行為由超類或者子類繼承某個(gè)接口,自行實(shí)現(xiàn)。這兩種做法都依賴與“實(shí)現(xiàn)”,這樣我們很容易被實(shí)現(xiàn)綁死,很難在后來改變行為(除非寫更多的代碼)。新的設(shè)計(jì)里,支付類將使用由接口所表示的行為,所以實(shí)際的“實(shí)現(xiàn)”并不會(huì)綁死在支付類中,這樣,支付類就不用在了解行為實(shí)現(xiàn)的細(xì)節(jié)。
來看一下新的類圖:
以及,看看Pay抽象類中統(tǒng)一后的方法代碼:
orderBehavior->orderPay(); } public function refund() { return $this->refundBehavior->refund(); } }
然后在實(shí)現(xiàn)的時(shí)候,子類就能這樣動(dòng)態(tài)實(shí)現(xiàn)
orderBehavior = new WxOrder(); //實(shí)現(xiàn)了微信支付的下單 $pay->orderPay(); //第三方支付同理 $pay = new SandPay(); $pay->orderBehavior = new SandOrder(); $pay->orderPay();
可能這時(shí)候有人會(huì)問,我明明可以直接就在具體類里實(shí)現(xiàn)這個(gè)方法,也不用多寫這么多類與接口,正常來說,支付也不會(huì)改變其實(shí)現(xiàn)方式。
是的,一般來說,支付是不會(huì)修改的,但是如果突然說現(xiàn)在不用第三方支付,全部都用微信支付,那么我們代碼的修改可能會(huì)很多了,但是用這種實(shí)現(xiàn)我們只需要改動(dòng)一個(gè)很小地方:
orderBehavior = new WxOrder(); //我們由于不用管實(shí)際的細(xì)節(jié),也不用做太多的代碼改動(dòng),而且由微信支付本來的穩(wěn)定實(shí)現(xiàn),我們也能很放心的說,代碼不會(huì)出現(xiàn)bug $pay->orderPay();
這一種實(shí)現(xiàn)方式,也符合了一個(gè)設(shè)計(jì)原則:
多用組合,少用繼承
這里支付對(duì)下單甚至退款的操作,實(shí)際的實(shí)現(xiàn)都不是通過繼承得到的,而是通過將其他類的結(jié)合,不僅可以將算法族封裝成類,更可以“在運(yùn)行時(shí)動(dòng)態(tài)改變行為”,只要行為對(duì)象符合正確的接口標(biāo)準(zhǔn)即可。
這個(gè)情況,你覺得是用了哪種設(shè)計(jì)模式?
1、 場景描述
在處理完多種支付的場景后,我們?cè)陂_始加入了第三方支付的代碼,在寫的過程發(fā)現(xiàn),下單操作和微信支付類似,我們需要在請(qǐng)求 之前,組裝請(qǐng)求必要參數(shù)、簽名,得到返回結(jié)果后,對(duì)數(shù)據(jù)驗(yàn)簽,然后進(jìn)行自己的業(yè)務(wù)邏輯,最后返回一個(gè)應(yīng)答。 同理,退款操作也是一樣:組裝請(qǐng)求必要參數(shù)、簽名等等,和下單操作幾乎處理邏輯的順序或者說結(jié)構(gòu)很相似,如果我們繼續(xù)這么 編寫,會(huì)發(fā)現(xiàn)很多重復(fù)代碼,這個(gè)時(shí)候要怎么處理呢?
2、 問題分析
在解決問題之前,先說一下一個(gè)重要的設(shè)計(jì)原則:
找出應(yīng)用中可能需要變化之處,把它們獨(dú)立出來,不要和那些不需要變化的代碼混在一起。
通俗來說,就是要善于發(fā)現(xiàn)現(xiàn)實(shí)中的變與不變,抽離不變的地方,使其能復(fù)用,然后讓變化的部分自行解決處理。 在這個(gè)場景中,很特殊的,我們發(fā)現(xiàn)不管是微信的下單、退款,還是第三方的下單、退款,他們業(yè)務(wù)的邏輯幾乎是一個(gè)流水線上出 來的,就是他們不變的地方,而變化的是什么呢?很明顯就是具體的實(shí)現(xiàn)業(yè)務(wù)不同,這部分應(yīng)該由業(yè)務(wù)自己實(shí)現(xiàn)。 這樣,我們將該描述用類圖表示如下:
而代碼具體如下:
generateRequestData(); $this->generateSign(); $this->request(); $this->verifiedSign(); $this->handleResponse(); $this->returnMsg(); } abstract protected function generateRequestData(); abstract protected function generateSign(); abstract protected function request(); abstract protected function handleResponse(); abstract protected function verifiedSign(); abstract protected function returnMsg(); } class WxOrder extends PayAction{ public function orderPay() { $this->doAction(); } }
只針對(duì)這一系列操作,我們可以寫成這個(gè)樣子,這樣所有的行為都一樣了,只需要實(shí)現(xiàn)自身不一樣的地方即可。
ROUND 3:結(jié)合的效果1、如果把第一種情況的結(jié)構(gòu)和第二種情況的結(jié)構(gòu),結(jié)合起來,最后是什么樣子呢,我們可以看一下:
這樣,整個(gè)結(jié)構(gòu)就很清晰了,客戶端調(diào)用實(shí)現(xiàn)了行為的下單或者退款類,不需要知道具體的細(xì)節(jié),并且可以動(dòng)態(tài)的改變行為的對(duì)象;而行為的操作的重復(fù)部分又被抽出來,只需要各自實(shí)現(xiàn)變化的部分,不變的部分都由抽象類PayAction先定義好,再由不一樣的支付類實(shí)現(xiàn)公共的部分:簽名與驗(yàn)簽,甚至最后固定的返回正確和錯(cuò)誤時(shí)的格式都是同一個(gè)支付里,相同的部分;最后不一樣的只有不同請(qǐng)求時(shí)候,不一樣的請(qǐng)求參數(shù),以及獲得返回參數(shù)后的不一樣的處理了。
類和接口的確比一開始的設(shè)計(jì)要多了不少,但是結(jié)構(gòu)非常清晰,而且修改的時(shí)候,可以很有針對(duì)性的修改,對(duì)于客戶端來說,調(diào)用是透明的,對(duì)于提供服務(wù)的我們來說,不管是新增一個(gè)支付方式,還是多了一個(gè)支付操作,我們都可以很好的增加代碼,不用修改現(xiàn)有代碼,而這個(gè)也是一個(gè)經(jīng)常說到的設(shè)計(jì)原則:
開閉原則:對(duì)修改關(guān)閉,對(duì)擴(kuò)展開放
第一和第二個(gè)場景,它們分別對(duì)應(yīng)的設(shè)計(jì)模式是什么?
第一種設(shè)計(jì)模式是:策略模式,而第二種是:模板方法模式
第一種我們可以清楚的看到,我們對(duì)于如何運(yùn)行一個(gè)行為的時(shí)候,我們是將其封裝在一個(gè)類中處理,并且,它們可以相互替換。算法的改變由客戶來決定,可以動(dòng)態(tài)的改變。
第二種我們可以看到的是,整個(gè)算法的結(jié)構(gòu)已經(jīng)被定義好,跟著預(yù)定好的模板來編寫我們的算法,就可以實(shí)現(xiàn)相似的功能有條不紊的編寫下去,不會(huì)出現(xiàn)多余的部分,并且可以專心的處理自身特別的業(yè)務(wù)邏輯。
所以,以后如果代碼的相關(guān)結(jié)構(gòu)很相似,可以選用模板方法模式來編寫;如果業(yè)務(wù)中的某些行為可以被抽象并且有需要?jiǎng)討B(tài)改變的時(shí)候,可以考慮策略模式來編寫。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/29352.html
摘要:面向?qū)ο笕筇卣骼^承性多態(tài)性封裝性接口。第五階段封裝一個(gè)屬于自己的框架框架封裝基礎(chǔ)事件流冒泡捕獲事件對(duì)象事件框架選擇框架。核心模塊和對(duì)象全局對(duì)象,,,事件驅(qū)動(dòng),事件發(fā)射器加密解密,路徑操作,序列化和反序列化文件流操作服務(wù)端與客戶端。 第一階段: HTML+CSS:HTML進(jìn)階、CSS進(jìn)階、div+css布局、HTML+css整站開發(fā)、 JavaScript基礎(chǔ):Js基礎(chǔ)教程、js內(nèi)置對(duì)...
摘要:面向?qū)ο笕筇卣骼^承性多態(tài)性封裝性接口。第五階段封裝一個(gè)屬于自己的框架框架封裝基礎(chǔ)事件流冒泡捕獲事件對(duì)象事件框架選擇框架。核心模塊和對(duì)象全局對(duì)象,,,事件驅(qū)動(dòng),事件發(fā)射器加密解密,路徑操作,序列化和反序列化文件流操作服務(wù)端與客戶端。 第一階段: HTML+CSS:HTML進(jìn)階、CSS進(jìn)階、div+css布局、HTML+css整站開發(fā)、 JavaScript基礎(chǔ):Js基礎(chǔ)教程、js內(nèi)置對(duì)...
摘要:設(shè)計(jì)模式無論是對(duì)于最底層的的編碼實(shí)現(xiàn)還是較高層的架構(gòu)設(shè)計(jì)都有著重要的指導(dǎo)作用。所謂光說不練假把式,今天我就把項(xiàng)目中常見的應(yīng)用場景涉及到的主要設(shè)計(jì)模式及其相關(guān)設(shè)計(jì)模式總結(jié)一下,用實(shí)例分析和對(duì)比的方式在一片文章中就把最常見的種設(shè)計(jì)模式梳理清楚。 設(shè)計(jì)模式無論是對(duì)于最底層的的編碼實(shí)現(xiàn)還是較高層的架構(gòu)設(shè)計(jì)都有著重要的指導(dǎo)作用。所謂光說不練假把式,今天我就把項(xiàng)目中常見的應(yīng)用場景涉及到的主要設(shè)計(jì)模...
摘要:為程序員金三銀四精心挑選的余道面試題與答案,歡迎大家向我推薦你在面試過程中遇到的問題我會(huì)把大家推薦的問題添加到下面的常用面試題清單中供大家參考。 為Java程序員金三銀四精心挑選的300余道Java面試題與答案,歡迎大家向我推薦你在面試過程中遇到的問題,我會(huì)把大家推薦的問題添加到下面的常用面試題清單中供大家參考。 前兩天寫的以下博客,大家比較認(rèn)可,熱度不錯(cuò),希望可以幫到準(zhǔn)備或者正在參加...
閱讀 3834·2021-09-06 15:00
閱讀 2171·2019-08-30 15:53
閱讀 3277·2019-08-23 16:44
閱讀 944·2019-08-23 15:19
閱讀 1391·2019-08-23 12:27
閱讀 4187·2019-08-23 11:30
閱讀 581·2019-08-23 10:33
閱讀 369·2019-08-22 16:05