做者:小傅哥
博客:https://bugstack.cnhtml
沉澱、分享、成長,讓本身和他人都能有所收穫!😄
爲何你的代碼那麼多ifelse
java
同類的業務、一樣的功能,怎麼就你能寫出來那麼多ifelse
。不少時候一些剛剛從校園進入企業的萌新,或者一部分從小公司跳槽到大企業的程序員,初次承接業務需求的時候,每每編碼還不成熟,常常一杆到底的寫需求。初次實現確實很快,可是後期維護和擴展就十分痛苦。由於一段代碼的可讀性閱讀他後期的維護成本也就越高。程序員
設計模式是能夠幫助你改善代碼
設計模式
不少時候你寫出來的ifelse
都是沒有考慮使用設計模式優化,就像;同類服務的不一樣接口適配包裝、同類物料不一樣組合的建造、多種獎品組合的營銷工廠等等。它們均可以讓你代碼中本來使用if
判斷的地方,變成一組組類和麪向對象的實現過程。安全
怎麼把設計模式和實際開發結合起來
微信
多從實際場景思考,只找到代碼優化的最佳點,不要能夠想着設計模式的使用。就像你最開始看設計模式適合,由於沒有真實的場景模擬案例,都是一些畫圓形、方形,對新人或者理解能力還不到的夥伴來講很不友好。因此即便學了半天 ,但實際使用仍是摸不着頭腦。函數
bugstack蟲洞棧
,回覆源碼下載
獲取(打開獲取的連接,找到序號18)工程 | 描述 |
---|---|
itstack-demo-design-7-01 | 使用一坨代碼實現業務需求 |
itstack-demo-design-7-02 | 經過設計模式優化改造代碼,產生對比性從而學習 |
橋接模式的主要做用就是經過將抽象部分與實現部分分離,把多種可匹配的使用進行組合。說白了核心實現也就是在A類中含有B類接口,經過構造函數傳遞B類的實現,這個B類就是設計的橋
。學習
那麼這樣的橋接模式,在咱們日常的開發中有哪些場景測試
JDBC多種驅動程序的實現、同品牌類型的臺式機和筆記本平板、業務實現中的多類接口同組過濾服務等。這些場景都比較適合使用橋接模式進行實現,由於在一些組合中若是有若是每個類都實現不一樣的服務可能會出現笛卡爾積,而使用橋接模式就能夠很是簡單。微信支付
隨着市場的競爭在支付服務行業出現了微信和支付寶還包括一些其餘支付服務,可是對於商家來講並不但願改變用戶習慣。就像若是個人地攤只能使用微信或者只能使用支付寶付款,那麼就會讓我顧客傷心,雞蛋灌餅也賣不動了。
在這個時候就出現了第三方平臺,把市面上綜合佔據市場90%以上的支付服務都集中到本身平臺中,再把這樣的平臺提供給店鋪、超市、地攤使用,同時支持人臉、掃描、密碼多種方式。
咱們這個案例就模擬一個這樣的第三方平臺來承接各個支付能力,同時使用自家的人臉讓用戶支付起來更加容易。那麼這裏就出現了多支付與多模式的融合使用,若是給每個支付都實現一次不一樣的模式,即便是繼承類也須要開發好多。並且隨着後面接入了更多的支付服務或者支付方式,就會呈爆炸似的擴展。
因此你如今能夠思考一下這樣的場景該如何實現?
產品經理說老闆要的需求,要儘快上,kpi你看着弄!
既然你逼我那就別怪我無情,尚未我一個類寫不完的需求!反正寫完就完事了,拿完績效也要走了每天逼着寫需求,代碼愈來愈亂心疼後面的兄弟3秒。
itstack-demo-design-7-01 └── src └── main └── java └── org.itstack.demo.design └── PayController.java
ifelse
,這個類實現了支付和模式的所有功能。public class PayController { private Logger logger = LoggerFactory.getLogger(PayController.class); public boolean doPay(String uId, String tradeId, BigDecimal amount, int channelType, int modeType) { // 微信支付 if (1 == channelType) { logger.info("模擬微信渠道支付劃帳開始。uId:{} tradeId:{} amount:{}", uId, tradeId, amount); if (1 == modeType) { logger.info("密碼支付,風控校驗環境安全"); } else if (2 == modeType) { logger.info("人臉支付,風控校驗臉部識別"); } else if (3 == modeType) { logger.info("指紋支付,風控校驗指紋信息"); } } // 支付寶支付 else if (2 == channelType) { logger.info("模擬支付寶渠道支付劃帳開始。uId:{} tradeId:{} amount:{}", uId, tradeId, amount); if (1 == modeType) { logger.info("密碼支付,風控校驗環境安全"); } else if (2 == modeType) { logger.info("人臉支付,風控校驗臉部識別"); } else if (3 == modeType) { logger.info("指紋支付,風控校驗指紋信息"); } } return true; } }
用戶ID
、交易ID
、金額
、渠道
、模式
,來控制支付方式。ifelse
應該是最差的一種寫法,即便寫ifelse
也是能夠優化的方式去寫的。@Test public void test_pay() { PayController pay = new PayController(); System.out.println("\r\n模擬測試場景;微信支付、人臉方式。"); pay.doPay("weixin_1092033111", "100000109893", new BigDecimal(100), 1, 2); System.out.println("\r\n模擬測試場景;支付寶支付、指紋方式。"); pay.doPay("jlu19dlxo111","100000109894",new BigDecimal(100), 2, 3); }
模擬測試場景;微信支付、人臉方式。 23:05:59.152 [main] INFO o.i.demo.design.pay.channel.Pay - 模擬微信渠道支付劃帳開始。uId:weixin_1092033111 tradeId:100000109893 amount:100 23:05:59.155 [main] INFO o.i.demo.design.pay.mode.PayCypher - 人臉支付,風控校驗臉部識別 23:05:59.155 [main] INFO o.i.demo.design.pay.channel.Pay - 模擬微信渠道支付風控校驗。uId:weixin_1092033111 tradeId:100000109893 security:true 23:05:59.155 [main] INFO o.i.demo.design.pay.channel.Pay - 模擬微信渠道支付劃帳成功。uId:weixin_1092033111 tradeId:100000109893 amount:100 模擬測試場景;支付寶支付、指紋方式。 23:05:59.156 [main] INFO o.i.demo.design.pay.channel.Pay - 模擬支付寶渠道支付劃帳開始。uId:jlu19dlxo111 tradeId:100000109894 amount:100 23:05:59.156 [main] INFO o.i.demo.design.pay.mode.PayCypher - 指紋支付,風控校驗指紋信息 23:05:59.156 [main] INFO o.i.demo.design.pay.channel.Pay - 模擬支付寶渠道支付風控校驗。uId:jlu19dlxo111 tradeId:100000109894 security:true 23:05:59.156 [main] INFO o.i.demo.design.pay.channel.Pay - 模擬支付寶渠道支付劃帳成功。uId:jlu19dlxo111 tradeId:100000109894 amount:100 Process finished with exit code 0
接下來使用橋接模式來進行代碼優化,也算是一次很小的重構。
從上面的ifelse
方式實現來看,這是兩種不一樣類型的相互組合。那麼就能夠把支付方式和支付模式進行分離經過抽象類依賴實現類的方式進行橋接,經過這樣的拆分後支付與模式實際上是能夠單獨使用的,當須要組合時候只須要把模式傳遞給支付便可。
橋接模式的關鍵是選擇的橋接點拆分,是否能夠找到這樣相似的相互組合,若是沒有就沒必要要非得使用橋接模式。
itstack-demo-design-7-02 └── src ├── main │ └── java │ └── org.itstack.demo.design.pay │ ├── channel │ │ ├── Pay.java │ │ ├── WxPay.java │ │ └── ZfbPay.java │ └── mode │ ├── IPayMode.java │ ├── PayCypher.java │ ├── PayFaceMode.java │ └── PayFingerprintMode.java └── test └── java └── org.itstack.demo.design.test └── ApiTest.java
橋接模式模型結構
Pay
是一個抽象類,往下是它的兩個支付類型實現;微信支付、支付寶支付。IPayMode
是一個接口,往下是它的兩個支付模型;刷臉支付、指紋支付。支付類型
× 支付模型
= 就能夠獲得相應的組合。public abstract class Pay { protected Logger logger = LoggerFactory.getLogger(Pay.class); protected IPayMode payMode; public Pay(IPayMode payMode) { this.payMode = payMode; } public abstract String transfer(String uId, String tradeId, BigDecimal amount); }
transfer
,以及橋接接口;IPayMode
,並在構造函數中用戶方自行選擇支付方式。IPayMode payMode
,這部分是橋接的核心。微信支付
public class WxPay extends Pay { public WxPay(IPayMode payMode) { super(payMode); } public String transfer(String uId, String tradeId, BigDecimal amount) { logger.info("模擬微信渠道支付劃帳開始。uId:{} tradeId:{} amount:{}", uId, tradeId, amount); boolean security = payMode.security(uId); logger.info("模擬微信渠道支付風控校驗。uId:{} tradeId:{} security:{}", uId, tradeId, security); if (!security) { logger.info("模擬微信渠道支付劃帳攔截。uId:{} tradeId:{} amount:{}", uId, tradeId, amount); return "0001"; } logger.info("模擬微信渠道支付劃帳成功。uId:{} tradeId:{} amount:{}", uId, tradeId, amount); return "0000"; } }
支付寶支付
public class ZfbPay extends Pay { public ZfbPay(IPayMode payMode) { super(payMode); } public String transfer(String uId, String tradeId, BigDecimal amount) { logger.info("模擬支付寶渠道支付劃帳開始。uId:{} tradeId:{} amount:{}", uId, tradeId, amount); boolean security = payMode.security(uId); logger.info("模擬支付寶渠道支付風控校驗。uId:{} tradeId:{} security:{}", uId, tradeId, security); if (!security) { logger.info("模擬支付寶渠道支付劃帳攔截。uId:{} tradeId:{} amount:{}", uId, tradeId, amount); return "0001"; } logger.info("模擬支付寶渠道支付劃帳成功。uId:{} tradeId:{} amount:{}", uId, tradeId, amount); return "0000"; } }
刷臉
、指紋
),都須要過指定的風控,才能保證支付安全。public interface IPayMode { boolean security(String uId); }
刷臉
public class PayFaceMode implements IPayMode{ protected Logger logger = LoggerFactory.getLogger(PayCypher.class); public boolean security(String uId) { logger.info("人臉支付,風控校驗臉部識別"); return true; } }
指紋
public class PayFingerprintMode implements IPayMode{ protected Logger logger = LoggerFactory.getLogger(PayCypher.class); public boolean security(String uId) { logger.info("指紋支付,風控校驗指紋信息"); return true; } }
密碼
public class PayCypher implements IPayMode{ protected Logger logger = LoggerFactory.getLogger(PayCypher.class); public boolean security(String uId) { logger.info("密碼支付,風控校驗環境安全"); return true; } }
@Test public void test_pay() { System.out.println("\r\n模擬測試場景;微信支付、人臉方式。"); Pay wxPay = new WxPay(new PayFaceMode()); wxPay.transfer("weixin_1092033111", "100000109893", new BigDecimal(100)); System.out.println("\r\n模擬測試場景;支付寶支付、指紋方式。"); Pay zfbPay = new ZfbPay(new PayFingerprintMode()); zfbPay.transfer("jlu19dlxo111","100000109894",new BigDecimal(100)); }
new WxPay(new PayFaceMode())
、new ZfbPay(new PayFingerprintMode())
橋接模式
的使用進行重構if邏輯部分,關於調用部分可使用抽象工廠
或策略模式
配合map結構,將服務配置化。由於這裏主要展現橋接模式,因此就不在額外多加代碼,避免喧賓奪主。模擬測試場景;微信支付、人臉方式。 23:14:40.911 [main] INFO o.i.demo.design.pay.channel.Pay - 模擬微信渠道支付劃帳開始。uId:weixin_1092033111 tradeId:100000109893 amount:100 23:14:40.914 [main] INFO o.i.demo.design.pay.mode.PayCypher - 人臉支付,風控校驗臉部識別 23:14:40.914 [main] INFO o.i.demo.design.pay.channel.Pay - 模擬微信渠道支付風控校驗。uId:weixin_1092033111 tradeId:100000109893 security:true 23:14:40.915 [main] INFO o.i.demo.design.pay.channel.Pay - 模擬微信渠道支付劃帳成功。uId:weixin_1092033111 tradeId:100000109893 amount:100 模擬測試場景;支付寶支付、指紋方式。 23:14:40.915 [main] INFO o.i.demo.design.pay.channel.Pay - 模擬支付寶渠道支付劃帳開始。uId:jlu19dlxo111 tradeId:100000109894 amount:100 23:14:40.915 [main] INFO o.i.demo.design.pay.mode.PayCypher - 指紋支付,風控校驗指紋信息 23:14:40.915 [main] INFO o.i.demo.design.pay.channel.Pay - 模擬支付寶渠道支付風控校驗。uId:jlu19dlxo111 tradeId:100000109894 security:true 23:14:40.915 [main] INFO o.i.demo.design.pay.channel.Pay - 模擬支付寶渠道支付劃帳成功。uId:jlu19dlxo111 tradeId:100000109894 amount:100 Process finished with exit code 0
刷臉
、指紋
、密碼
,的組合從而體現了橋接模式的在這類場景中的合理運用。簡化了代碼的開發,給後續的需求迭代增長了很好的擴展性。