關于同一接口有多個不同實現的設計方案
前言
最近公司做了一個銀行相關的項目,告訴我公司對接了多個銀行的支付,每個銀行都有對應的接口要去對接,比如:交易申請,交易取消,支付,回單,交易記錄查詢等等;這次讓我寫的是工商銀行的支付接口對接,于是我看了下代碼,因為比較敏感,所以給大家簡單寫一下怎么實現的。
public static BankService createService(String bankCode) throws Exception{if (bankCode == null || bankCode.length() == 0){throw new ClassNotFoundException("BankCode: is null !");}else if(BankCode.ZHENGZHOU_BANK.getCode().equals(bankCode)){return ApplicationContextUtils.getBean(ZhengzhouBankServiceImpl.class);}else if(BankCode.ZHONGYUAN_BANK.getCode().equals(bankCode)){return ApplicationContextUtils.getBean(ZhongyuanBankServiceImpl.class);}else if(BankCode.YOUZHENG_BANK.getCode().equals(bankCode)){return ApplicationContextUtils.getBean(YouzhengBankServiceImpl.class);}else if(BankCode.NONGSHANG_BANK.getCode().equals(bankCode)){return ApplicationContextUtils.getBean(NongshangBankServiceImpl.class);}else if(BankCode.GONGSHANG_BANK.getCode().equals(bankCode)){return ApplicationContextUtils.getBean(GongshangBankServiceImpl.class);}else if(BankCode.XINJIANGNCXYS_BANK.getCode().equals(bankCode)) {NcxysBankServiceImpl bean = ApplicationContextUtils.getBean(NcxysBankServiceImpl.class);return bean;}else if(BankCode.JINAHANG_BANK.getCode().equals(bankCode)){return ApplicationContextUtils.getBean(JianSheBankServiceImpl.class);}else if(BankCode.XINJIANGNNONGYE_BANK.getCode().equals(bankCode)){return ApplicationContextUtils.getBean(NongYeBankServiceImpl.class);}else if(BankCode.ZHONGUO_BANK.getCode().equals(bankCode)){return ApplicationContextUtils.getBean(ZhongGuoBankServiceImpl.class);}else if(BankCode.PINGAN_BANK.getCode().equals(bankCode)){return ApplicationContextUtils.getBean(PingAnBankServiceImpl.class);}else if(BankCode.HAINANNCXYS_BANK.getCode().equals(bankCode)){return ApplicationContextUtils.getBean(HaiNanNcxysBankServiceImpl.class);}else if(BankCode.HAMI_BANK.getCode().equals(bankCode)){return ApplicationContextUtils.getBean(HaMiBankServiceImpl.class);}else{throw new ClassNotFoundException("BankCode: " + bankCode + " 暫未開通接口服務 !");}}
看上去是不是有點頭皮發麻,于是我想到有些其他的場景也會這樣,比如訂單的流轉,可能每個狀態的訂單都會有不同的實現,是不是可以優化一下,不讓代碼出現這么多的if else。
整活
利用抽象類
抽象類,大家都知道,我們可以把接口寫在抽象類里,也可以把方法在抽象類里實現,我們可以借助抽象類的特性,在抽象類中定義好方法和接口,如果這個功能所有的實現類都要實現,那么我們就把接口定義成接口,如果只是某些實現類需要實現的方法,我們就把接口給它實現,直接上代碼!
比如pay方法,所有的銀行都必須要實現的方法,我就給它定義成抽象方法;transaction方法,只是某個實現類需要實現的方法,我就給直接把方法實現,并拋出異常,意識是沒有權限訪問。
實現抽象類
在實現抽象類之前,我們要定義每個實現類的編碼,這個一定是寫死的,比方訂單狀態,1就是待接單2就是待支付,這個是不可能變得;銀行編碼001就是工商銀行也永遠不會變的。再次上代碼!
我在每個實現類的@Service上都定義了實現類的命名,然后注意,三個實現類我都實現了pay方法,這是必須的,不實現就報錯,但是GongShangHandler還實現了transaction方法,那調用這個方法的時候就會進入到具體的實現類里,不會拋出NO POWER的異常。
controller的編寫
使用spring的特性,用map來接受這些Service,map的key就是我們@service里的命名,也就是001,002,003。然后我們直接用map去get傳過來code編碼,直接就可以獲取到實現類,就不需要多個if else判斷了。
測試結果