因爲責任鏈大多數都是不純的狀況,本案例中,只要校驗失敗就直接返回,不繼續處理接下去責任鏈中的其餘校驗邏輯了,故而出現若是某個部分邏輯是要由多個校驗器組成一個整理的校驗邏輯的話,則此責任鏈模式則顯現出了它的不足之處了。(責任鏈模式的具體運用以及原理請參見筆者github wiki 2 責任鏈模式)java
關於接口適配器模式原理以及使用場景請參見筆者github wiki 12 適配器模式 。git
事例代碼請參見工程design-patterns-business
中的defaultmethod
包下的代碼。
default medthod
default
關鍵字用來擴展已有的接口,在對已有接口的使用不產生任何影響的狀況下,添加擴展。github
好比咱們已經投入使用的接口須要拓展一個新的方法,在Java8之前,若是爲一個使用的接口增長一個新方法,則咱們必須在全部實現類中添加該方法的實現,不然編譯會出現異常。若是實現類數量少而且咱們有權限修改,可能會工做量相對較少。若是實現類比較多或者咱們沒有權限修改實現類源代碼,這樣可能就比較麻煩。而默認方法則解決了這個問題,它提供了一個實現,當沒有顯示提供其餘實現時就採用這個實現,這樣新添加的方法將不會破壞現有代碼。
默認方法的另外一個優點是該方法是可選的,子類能夠根據不一樣的需求Override默認實現。數據庫
例如,咱們定義一個集合接口,其中有增、刪、改等操做。若是咱們的實現類90%都是以數組保存數據,那麼咱們能夠定義針對這些方法給出默認實現,而對於其餘非數組集合或者有其餘相似業務,能夠選擇性複寫接口中默認方法。
」類優先」 原則segmentfault
接口衝突原則設計模式
因爲系統業務需求的變動,目前有兩種業務需求,數組
根據第2節的改進方式能夠知道,咱們有兩種方式改進以上邏輯。ide
代碼參見2.1版本的,地址爲: https://github.com/landy8530/...
若採用適配器模式,此處咱們會採用接口適配器模式。單元測試
接口須要多增長一個不用鏈式調用的校驗方法,定義以下,測試
/** * 業務校驗統一接口,增長了接口的默認方法實現,這樣能夠更加方便且自由選擇實現接口的哪些方法。 * @author landyl * @create 10:32 AM 05/09/2018 * @version 2.0 * @since 1.0 */ public interface Validator<R extends RequestDetail,F extends RequestFile> { /** * 須要引入責任鏈的時候,則採用此方法 * @param detail * @param chain * @return * @throws BusinessValidationException */ String doValidate(R detail, F file, ValidatorChain chain) throws BusinessValidationException; /** * 不須要責任鏈的時候,則能夠直接調用此方法的實現便可 * @param detail * @return * @throws BusinessValidationException */ boolean doValidate(R detail, F file) throws BusinessValidationException; }
適配器類定義以下抽象類,
/** * @author: landy * @date: 2019/5/19 14:48 * @description: */ public abstract class ValidatorAdapter implements Validator<RequestDetail, RequestFile> { public String doValidate(RequestDetail detail, RequestFile file, ValidatorChain chain) throws BusinessValidationException { boolean isValid = this.doValidate(detail, file); //校驗失敗了,就直接返回 if(!isValid) { if(detail.getValidationResult() != null) { return detail.getValidationResult().getResultMsg(); } } //不然往責任鏈中下一個校驗器進行處理 return chain.doValidate(detail, file); } @Override public boolean doValidate(RequestDetail detail, RequestFile file) throws BusinessValidationException { return true; } }
如此一來,由於增長了原有接口中的方法,則須要在每一個實現類中都增長一個實現方法,雖然有以上的適配器類,可是也要把以前實現接口改成繼承該適配器類,即 ValidatorAdapter
類。好比,
/** * @author landyl * @create 2:57 PM 05/09/2018 */ @Component(ValidatorConstants.BEAN_NAME_CUSTOMER_IS_ACTIVE) public class IsActiveValidator extends ValidatorAdapter { @Override public boolean doValidate(RequestDetail detail, RequestFile file) throws BusinessValidationException { if (StringUtils.isNotEmpty(detail.getIsActive()) && !"0".equals(detail.getIsActive()) && !"1".equals(detail.getIsActive())) { String result = "An invalid Is Active setting was provided. Accepted Value(s): 0, 1 (0 = No; 1 = Yes)."; detail.bindValidationResult(Constants.INVALID_IS_ACTIVE,result); return false; } return true; } }
並且,由於適配器類中的參數都是RequestDetail
和 RequestFile
類,故而子類可能須要作強制轉換操做,如:
@Component(ValidatorConstants.BEAN_NAME_CUSTOMER_BUSINESS_LINE) public class BusinessLineValidator extends ValidatorAdapter { public String doValidate(RequestDetail detail, RequestFile file, ValidatorChain chain) throws BusinessValidationException { if(detail instanceof CustomerRequestDetail) { CustomerRequestDetail crd = (CustomerRequestDetail)detail; String result = validateBusinessLineLogic(crd); if(!Constants.VALID.equals(result)){ return result; } } return chain.doValidate(detail,file); } ... }
侷限性比較多。
代碼參見2.0版本,地址爲: https://github.com/landy8530/... ,後續也會merge到master版本。
接口定義以下,採用默認方法實現,
/** * 業務校驗統一接口,增長了接口的默認方法實現,這樣能夠更加方便且自由選擇實現接口的哪些方法。 * @author landyl * @create 10:32 AM 05/09/2018 * @version 2.0 * @since 1.0 */ public interface Validator<R extends RequestDetail,F extends RequestFile> { /** * 須要引入責任鏈的時候,則採用此方法 * @param detail * @param chain * @return * @throws BusinessValidationException */ default String doValidate(R detail, F file, ValidatorChain chain) throws BusinessValidationException { boolean isValid = this.doValidate(detail, file); //校驗失敗了,就直接返回 if(!isValid) { if(detail.getValidationResult() != null) { return detail.getValidationResult().getResultMsg(); } } //不然往責任鏈中下一個校驗器進行處理 return chain.doValidate(detail, file); } /** * 不須要責任鏈的時候,則能夠直接調用此方法的實現便可 * @param detail * @return * @throws BusinessValidationException */ default boolean doValidate(R detail, F file) throws BusinessValidationException { return true; } }
因而可知,其實此處的默認方法,就是上節中的適配器類的實現方式而已,並且對於後續的實現類而言,無須變更(針對不須要改動業務邏輯的類而言)。即便針對須要變更業務邏輯的類,也只是改動部分而已,並且不須要類型強制轉換操做。避免了沒必要要的異常出現。
通過以上代碼實現能夠發現,默認接口實現有其很是明顯的優點,即擁抱變化,擴展已有接口,向後兼容。
具體的測試代碼能夠參見相應版本的github單元測試代碼便可。