[程式碼結構設計]根據不同條件使用不同實現類的業務程式碼設計
場景
此時有一個場景,需要設計一個根據不同的狀態和條件採用不同的業務處理方式。
這樣大家可能不是太理解。舉個例子,現在大街小巷上的商戶都採用了聚合支付的支付方式,聚合支付也就是商戶櫃檯前放了一個支援支付寶、微信、京東錢包、銀聯等等的二維碼,使用者可以通過任意一款支付APP進行支付。
解決思路
思路①
對每個支付渠道進行定義列舉型別
public enum PayWay { ALI_PAY, WECHAT_PAY; }
然後在每個對應的service上定義註解,表示對應哪種支付方式
@Pay(PayWay.ALI_PAY) public class AliPayServiceImpl implements PayService{}
但是仔細思考後,還是存在一些問題
-
如果增加一個支付方式後還需要修改,
PayWay
這個列舉型別 -
在程式中,仍需要根據不同的條件做
if else
判斷PayWay
,增加支付方式還是得修改原有的判斷邏輯。虛擬碼如下
if("xxx" == "aliPay"){ } else if("xxx" == "wechatPay"){ } //如果增加支付方式還是得增加else if
思路②
在思路①中存在一些問題,首當其衝的就是if else
判斷問題。先思考一下這個if else
的作用是什麼?
答:根據思路①描述,這個if else
是用來確定採用哪種支付方式。
我們可以將這塊程式碼抽離出來,讓對應的業務實現類實現自己的邏輯實現,然後根據返回值true
或者false
決定是否過濾掉這個業務實現類。介面定義如下,SupportBean
是封裝的一個實體
boolean isSupport(SupportBean supportBean);
然後在各個業務實現類都實現自己的isSupport方法,虛擬碼如下
@Override public boolean isSupport(SupportBean supportBean) { if (supportBean.getType() == "xxx"){ return true; } return false; }
設計
注:只提供一個架子
介面定義
Service介面定義,一個業務執行方法execute(引數自行新增),一個isSupport方法(返回true
或者false
)
public interface Service { void execute(); boolean isSupport(SupportBean supportBean); }
業務實現類
這裡execute方法只是在控制檯列印字串。isSupport方法對SupportBean中的supportNum進行取餘,判斷餘數是否等於0,是則返回true。
類似的實現還有兩個,這裡就不貼出來了。
@Component public class AServiceImpl implements Service { @Override public void execute() { System.out.println("A execute"); } @Override public boolean isSupport(SupportBean supportBean) { return supportBean.getSupportNum() % 3 == 0; } }
接下來在定義一個幫助類
幫助類
@Component public class Helper { @Autowired private List<Service> services; public void execute(SupportBean supportBean){ Service s = services.stream() .filter((service) -> service.isSupport(supportBean)) .findFirst()//NPE異常 .orElse(null); if (s != null){ s.execute(); } } }
通過工具類的execute方法來獲取對應的業務實現類執行的結果,以及對傳入的引數進行校驗處理等。
需要注意的是Lambda表示式的findFirst()會出現NullPointException異常。因為filter對list進行過濾,會存在過濾完list的長度為0,如果此時在呼叫findFirst則會丟擲NullPointException。可以將上面的程式碼修改為如下程式碼,這樣就可以避免NPE了
Service s = services.stream() .filter((service) -> service.isSupport(supportBean)) .map(Optional::ofNullable) .findFirst() .flatMap(Function.identity()) .orElse(null);
測試
新增一個springboot測試類和一個測試方法。
在contextLoads測試中呼叫幫助類Helper的execute方法
@RunWith(SpringRunner.class) @SpringBootTest public class ApplicationTests { @Autowired private Helper Helper; @Test public void contextLoads() { Helper.execute(new SupportBean(3)); } }
測試結果
A execute
擴充套件
在Lambda表示式中是先將業務實現類進行過濾,然後獲取第一個業務實現類並執行。
如果此時過濾存在多個業務實現類,而又不能確定優先順序,這時需要如何進行擴充套件呢?
其實很簡單,先在Service介面中定義一個getPriority
方法
int getPriority();
然後各自的實現類實現對應的getPriority
方法
接著修改Lambda表示式即可,在filter後增加sorted方法即可對業務實現類進行排序
Service s = services.stream() .filter((service) -> service.isSupport(supportBean)) .sorted(Comparator.comparing(Service::getPriority)) .map(Optional::ofNullable) .findFirst() .flatMap(Function.identity()) .orElse(null);
總結
整個大體框架基本都搭建完成,如需擴充套件只需要增加對應的業務實現類,而不用去修改其他類的程式碼。就連之前設計的列舉都可以不用,可擴充套件性大大提升。如需使用,只需修改對應的入參和對應的名稱即可。
ofollow,noindex" target="_blank">Github地址
如果對你有收穫,歡迎star、歡迎fork
如果你也有類似的經驗,歡迎加入,一起共建