西安網(wǎng)站建設(shè)云李百度知道合伙人官網(wǎng)登錄入口
前言
筆者是金融保險行業(yè),有這么一種場景,業(yè)務(wù)員錄完單后提交核保,這時候系統(tǒng)會對保單數(shù)據(jù)進行校驗,如不允許手續(xù)費超限校驗,客戶真實性校驗、費率限額校驗等等,當(dāng)校驗一多時,維護起來特別麻煩,代碼耦合度太高。
這里使用責(zé)任鏈模式,將每個校驗?zāi)K之間互相獨立,在后面新增校驗時,只需要往容器中插入即可,且可以給每個模塊賦予優(yōu)選級進行排序,利于管理。與Spring框架結(jié)合,利于類的管理。
正文
處理器模板
public interface CheckProcessor {/*** 邏輯處理* @param policyInfo* @param exposeProcessor*/public void invoke(PolicyInfo policyInfo,ExposeProcessor exposeProcessor) throws Exception;
}
處理器實現(xiàn)類
手續(xù)費校驗器
public class CommissionRateCheckProcessor implements CheckProcessor {@Overridepublic void invoke(PolicyInfo policyInfo, ExposeProcessor exposeProcessor) throws Exception {System.out.println("完成手續(xù)費校驗");//調(diào)用下個處理器exposeProcessor.invoke(policyInfo);}
}
客戶真實性校驗器
public class CustomerCheckProcessor implements CheckProcessor {@Overridepublic void invoke(PolicyInfo policyInfo, ExposeProcessor exposeProcessor) throws Exception {System.out.println("完成客戶真實性校驗");//調(diào)用下個處理器exposeProcessor.invoke(policyInfo);}
}
保險費率校驗器
public class PremiumRateCheckProcessor implements CheckProcessor {@Overridepublic void invoke(PolicyInfo policyInfo, ExposeProcessor exposeProcessor) throws Exception {System.out.println("完成保險費率校驗");//調(diào)用下個處理器exposeProcessor.invoke(policyInfo);}
}
入口管理類
public class ExposeProcessor {private int index;private static List<CheckProcessor> processor=new ArrayList();static {setProcessor(new CustomerCheckProcessor());setProcessor(new CommissionRateCheckProcessor());setProcessor(new PremiumRateCheckProcessor());}/*** 處理器*/public void invoke(PolicyInfo policyInfo) throws Exception {//獲取容器中所有的處理器List processors = getProcessors();if (processors.size()==0||index==processors.size()){return;}//根據(jù)指針指向,調(diào)用處理器。并把指針指向下一個CheckProcessor processor = (CheckProcessor)processors.get(index++);//調(diào)用處理器processor.invoke(policyInfo,this);}/*** 處理器集*/private List getProcessors(){return processor;}public static void setProcessor(CheckProcessor checkProcessor){processor.add(checkProcessor);}}
- 獲取容器中的校驗器
- 校驗是否往下執(zhí)行,如果處理器數(shù)量為空,或者當(dāng)前指針已經(jīng)指向尾部時,則不再往下執(zhí)行
- 將管理器以及請求參數(shù)傳遞到處理器中進行處理
- 處理器執(zhí)行完畢后,調(diào)用管理器的invoke方法來啟動責(zé)任鏈中的下個處理器
測試用例
public static void main(String[] args) {ExposeProcessor exposeProcessor=new ExposeProcessor();try {exposeProcessor.invoke(new PolicyInfo());} catch (Exception e) {e.printStackTrace();}}
以前代碼有很多可以改進的地方,如與IOC框架結(jié)合,將每個處理器交給IOC容器進行管理,在獲取處理器方法中可以直接從IOC容器中獲取CheckProcessor 類型的所有實現(xiàn)類。
結(jié)合Spring IOC
@Service
public class ExposeProcessor implements ApplicationContextAware {private ApplicationContext applicationContext;private int index;private List<CheckProcessor> processor=new ArrayList();/*** 處理器*/public void invoke(PolicyInfo policyInfo) throws Exception {List processors = getProcessors();if (processors.size()==0||index==processors.size()){return;}CheckProcessor processor = (CheckProcessor)processors.get(index++);processor.invoke(policyInfo,this);}/*** 處理器集*/private List getProcessors(){Map<String, CheckProcessor> beansOfType = this.applicationContext.getBeansOfType(CheckProcessor.class);return beansOfType.values().stream().collect(Collectors.toList());}public void setProcessor(CheckProcessor checkProcessor){processor.add(checkProcessor);}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext=applicationContext;}
}
- 管理類實現(xiàn)ApplicationContextAware接口,并重寫其setApplicationContext方法,將IOC上下文對象保存下來。
- 從IOC容器中獲取類型為CheckProcessor 的類
- 將管理類加上@Service注解交由IOC容器進行管理
- 在所有的校驗器實現(xiàn)類上都加上@Service注解,交由IOC容器管理
測試:
public static void main(String[] args) {//創(chuàng)建Spring IOC容器,開啟注解掃碼AnnotationConfigApplicationContext annotationConfigApplicationContext=new AnnotationConfigApplicationContext("com.mashibing.dp.intepreter");//獲取管理類ExposeProcessor exposeProcessor= (ExposeProcessor) annotationConfigApplicationContext.getBean("exposeProcessor");try {exposeProcessor.invoke(new PolicyInfo());} catch (Exception e) {e.printStackTrace();}}
由于項目非Spring web項目,所以必須啟動Spring IOC容器,指定包路徑對注解進行掃碼,這樣才能將類交由容器進行管理,不然獲取會為空。
總結(jié)
責(zé)任鏈模式有多種寫法,具體需要根據(jù)業(yè)務(wù)場景進行定制化開發(fā)。
責(zé)任鏈模式的優(yōu)點:
- 降低耦合度。它將請求的發(fā)送者和接收者解耦
- 簡化了對象。使得對象不需要知道鏈的結(jié)構(gòu)。
- 增強給對象指派職責(zé)的靈活性。通過改變鏈內(nèi)的成員或者調(diào)動它們的次序,允許動態(tài)地新增或者刪除責(zé)任。
- 增加新的請求處理類很方便。
責(zé)任鏈模式的缺點:
- 不能保證請求一定被接收。
- 系統(tǒng)性能將受到一定影響,而且在進行代碼調(diào)試時不太方便,可能會造成循環(huán)調(diào)用。
- 可能不容易觀察運行時的特征,有礙于除錯。