此時有一個場景,須要設計一個根據不一樣的狀態和條件採用不一樣的業務處理方式。java
這樣你們可能不是太理解。舉個例子,如今大街小巷上的商戶都採用了聚合支付的支付方式,聚合支付也就是商戶櫃檯前放了一個支持支付寶、微信、京東錢包、銀聯等等的二維碼,用戶能夠經過任意一款支付APP進行支付。git
對每一個支付渠道進行定義枚舉類型github
public enum PayWay {
ALI_PAY,
WECHAT_PAY;
}
複製代碼
而後在每一個對應的service上定義註解,表示對應哪一種支付方式spring
@Pay(PayWay.ALI_PAY)
public class AliPayServiceImpl implements PayService {}
複製代碼
可是仔細思考後,仍是存在一些問題springboot
PayWay
這個枚舉類型if else
判斷PayWay
,增長支付方式仍是得修改原有的判斷邏輯。僞代碼以下if("xxx" == "aliPay"){
} else if("xxx" == "wechatPay"){
}
//若是增長支付方式仍是得增長else if
複製代碼
在思路①中存在一些問題,首當其衝的就是if else
判斷問題。先思考一下這個if else
的做用是什麼?bash
答:根據思路①描述,這個if else
是用來肯定採用哪一種支付方式。微信
咱們能夠將這塊代碼抽離出來,讓對應的業務實現類實現本身的邏輯實現,而後根據返回值true
或者false
決定是否過濾掉這個業務實現類。接口定義以下,SupportBean
是封裝的一個實體框架
boolean isSupport(SupportBean supportBean);
複製代碼
而後在各個業務實現類都實現本身的isSupport方法,僞代碼以下ide
@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);
複製代碼
整個大致框架基本都搭建完成,如需擴展只須要增長對應的業務實現類,而不用去修改其餘類的代碼。就連以前設計的枚舉均可以不用,可擴展性大大提高。如需使用,只需修改對應的入參和對應的名稱便可。 Github地址 若是對你有收穫,歡迎star、歡迎fork 若是你也有相似的經驗,歡迎加入,一塊兒共建