場景
此時有一個場景首量,需要設計一個根據(jù)不同的狀態(tài)和條件采用不同的業(yè)務處理方式。
這樣大家可能不是太理解进苍。舉個例子加缘,現(xiàn)在大街小巷上的商戶都采用了聚合支付的支付方式,聚合支付也就是商戶柜臺前放了一個支持支付寶觉啊、微信拣宏、京東錢包、銀聯(lián)等等的二維碼杠人,用戶可以通過任意一款支付APP進行支付勋乾。
解決思路
思路①
對每個支付渠道進行定義枚舉類型
public enum PayWay {
ALI_PAY,
WECHAT_PAY;
}
然后在每個對應的service上定義注解宋下,表示對應哪種支付方式
@Pay(PayWay.ALI_PAY)
public class AliPayServiceImpl implements PayService {}
但是仔細思考后,還是存在一些問題
- 如果增加一個支付方式后還需要修改辑莫,
PayWay
這個枚舉類型 - 在程序中学歧,仍需要根據(jù)不同的條件做
if else
判斷PayWay
,增加支付方式還是得修改原有的判斷邏輯各吨。偽代碼如下
if("xxx" == "aliPay"){
} else if("xxx" == "wechatPay"){
}
//如果增加支付方式還是得增加else if
思路②
在思路①中存在一些問題枝笨,首當其沖的就是if else
判斷問題。先思考一下這個if else
的作用是什么揭蜒?
答:根據(jù)思路①描述伺帘,這個if else
是用來確定采用哪種支付方式。
我們可以將這塊代碼抽離出來忌锯,讓對應的業(yè)務實現(xiàn)類實現(xiàn)自己的邏輯實現(xiàn)伪嫁,然后根據(jù)返回值true
或者false
決定是否過濾掉這個業(yè)務實現(xiàn)類。接口定義如下偶垮,SupportBean
是封裝的一個實體
boolean isSupport(SupportBean supportBean);
然后在各個業(yè)務實現(xiàn)類都實現(xiàn)自己的isSupport方法,偽代碼如下
@Override
public boolean isSupport(SupportBean supportBean) {
if (supportBean.getType() == "xxx"){
return true;
}
return false;
}
設計
注:只提供一個架子
接口定義
Service接口定義张咳,一個業(yè)務執(zhí)行方法execute(參數(shù)自行添加),一個isSupport方法(返回true
或者false
)
public interface Service {
void execute();
boolean isSupport(SupportBean supportBean);
}
業(yè)務實現(xiàn)類
這里execute方法只是在控制臺打印字符串似舵。isSupport方法對SupportBean中的supportNum進行取余脚猾,判斷余數(shù)是否等于0,是則返回true砚哗。
類似的實現(xiàn)還有兩個龙助,這里就不貼出來了。
@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方法來獲取對應的業(yè)務實現(xiàn)類執(zhí)行的結果蛛芥,以及對傳入的參數(shù)進行校驗處理等提鸟。
需要注意的是Lambda表達式的findFirst()會出現(xiàn)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表達式中是先將業(yè)務實現(xiàn)類進行過濾庐船,然后獲取第一個業(yè)務實現(xiàn)類并執(zhí)行银酬。
如果此時過濾存在多個業(yè)務實現(xiàn)類,而又不能確定優(yōu)先級筐钟,這時需要如何進行擴展呢揩瞪?
其實很簡單,先在Service接口中定義一個getPriority
方法
int getPriority();
然后各自的實現(xiàn)類實現(xiàn)對應的getPriority
方法
接著修改Lambda表達式即可盗棵,在filter后增加sorted方法即可對業(yè)務實現(xiàn)類進行排序
Service s = services.stream()
.filter((service) -> service.isSupport(supportBean))
.sorted(Comparator.comparing(Service::getPriority))
.map(Optional::ofNullable)
.findFirst()
.flatMap(Function.identity())
.orElse(null);
總結
整個大體框架基本都搭建完成壮韭,如需擴展只需要增加對應的業(yè)務實現(xiàn)類北发,而不用去修改其他類的代碼。就連之前設計的枚舉都可以不用喷屋,可擴展性大大提升琳拨。如需使用,只需修改對應的入?yún)⒑蛯拿Q即可屯曹。
Github地址
如果對你有收獲狱庇,歡迎star、歡迎fork
如果你也有類似的經(jīng)驗恶耽,歡迎加入密任,一起共建