文章本來是上周要寫的,結果一拖再拖就拖到了今天。
最近在給系統做一些重構工作,至於為什麼要重構其實可以另開一個話題來展開,簡單來說,如果系統能正常跑就沒必要為了重構而重構,重構真正目的,主要是為了適應產品的迭代,讓系統保持良好的擴展性。
我在重構過程中,發現支付邏輯充斥着壞味道,主要代碼是下面這樣的,我把實現的細節都省略了,當然實際代碼比這個要長很多。
defpay(pay_type):ifpay_type=='alipay':alipay.pay()elifpay_type=='wechat':wechat.pay()elifpay_type=='unionpay':unionpay.pay()這段代碼的使用場景是滿足用戶可以選擇不同的支付方式完成付款操作,對應後端的代碼,你肯定能想到最簡單的實現方式就是上面的if ... else 語句。
隨着你的業務不斷擴大,產品經理跑過來跟你說,還需要接入多種支付方式,你的if else 代碼也跟着越來越長了。這帶來的一個問題就是系統的可擴展性差,後續的維護會變得舉步維艱。
在《重構》這本書,講到一個重構的原則,面對冗長的if else 語句, 我們可以利用面向對象的多態特性將if else 語句替換掉。
什麼是多態多態(Polymorphism)這個概念最早來自於生物學,表示的是同一物種在同一種群中存在兩種或多種明顯不同的表型。比如:在南美種群中存在兩種顏色的美洲虎:淺黃色的和黑色的。
在面向對象編程思想中,這個概念表達的是具有共性的類型,在執行相同的行為時,會體現出不同的實現方式。我們可以簡稱為:相同的行為,不同的實現。
在支付這個場景中,支付方式就是一種典型的多態,無論是支付寶還是微信或者是其他支付,他們都有一種相同的行為:提供支付功能,可以肯定的是不同的支付方式都有它自己的不同的實現方式。
那麼,如何將多態這種特性應用在我們的代碼中來呢?
第一步:給每一種支付類型定義一個類,裡面的pay方法用來實現具體的支付邏輯,對應每一個條件分支
classPay:defpay(self):raiseNotImplementedError()classAlipay(Pay):defpay(self):#這是支付寶的實現方式classWechatPay(Pay):defpay(self):#這是微信支付的實現方式我這裡使用了面向對象中另一個特性:繼承。通過繼承,讓每一個具體的支付類型都必須實現pay方法。當然繼承是可選的,因為在動態語言python中,多態不需要建立在繼承的基礎之上,只需要有 pay方法,不管是不是Pay的子類都可以當做一種支付方式類處理。
第二步:構建支付實例
我們可以用一個字典或者工廠方法來實現通過一個支付類型來找到對應的具體支付實例對象。
lookup={"alipay":Alipay(),"wechat":Wechatpay()}第三步:替換 if else
defpay(pay_type):lookup.get(pay_type).pay()現在再來看pay函數是不是簡單多了,和冗長的if else 語句說再見吧
如果未來需要增加其他支付方式,我們完全不需要再去修改pay函數,你只要去實現一個XxxPay的類就可以。
if ... else 就這樣被幹掉了。
最後,我想告訴大家的是,並不是什麼場景都非要用多態來解決 if else 語句的。如果 if else 中的邏輯本來就很清晰,就沒必要生搬硬套用多態去解決了。
劉志軍,一個寫了10+年代碼的碼農,歡迎關注