如何巧用設計模式【模板+工廠】來實現【聚合支付平臺非同步回撥】
核心設計要點
AbstractClass : 抽象類,定義並實現一個模板方法。這個模板方法定義了演算法的骨架,而邏輯的組成步驟在相應的抽象操作中,推遲到子類去實現。
ConcreteClass : 實現父類所定義的一個或多個抽象方法。
模版方法抽象類
/** * * @description: 使用模版方法重構非同步回撥程式碼 */ @Slf4j @Component public abstract class AbstractPayCallbackTemplate { /** * 非同步回撥業務 */ public String asyncCallBack() { // 1. 支付回撥驗證引數 Map<String, String> verifySignatureMap = verifySignature(); // 2. 引數驗證成功,寫入日誌中 payLog(verifySignatureMap); String analysisCode = verifySignatureMap.get("analysisCode"); if (!analysisCode.equals(PayConstant.RESULT_PAYCODE_200)) { return resultFail(); } // 3. 執行回撥非同步相關邏輯 return asyncService(verifySignatureMap); } /** * 使用多執行緒非同步寫入日誌 */ @Async protected void payLog(Map<String,String> verifySignatureMap){ log.info(">>>>>>>>>>第二步 寫入payLog........{}",verifySignatureMap); } /** * 實現業務解析操作 */ protected abstract String asyncService(Map<String,String> verifySignatureMap); /** * 非同步返回成功結果 */ protected abstract String resultSuccess(); /** * 非同步返回失敗結果 */ protected abstract String resultFail(); /** * 支付回撥驗證引數 */ protected abstract Map<String,String> verifySignature(); }
具體實現模版
①AliPayCallbackTemplate
/** * @title: AliPayCallbackTemplate */ @Component @Slf4j public class AliPayCallbackTemplate extends AbstractPayCallbackTemplate { @Override protected Map<String, String> verifySignature() { //>>>>支付寶回撥報文虛擬碼>>>> log.info(">>>>>第一步 解析支付寶資料報文.....verifySignature()"); Map<String, String> verifySignature = new HashMap<>(); verifySignature.put("price", "10000"); verifySignature.put("orderDes", "充值會員"); // 支付狀態為1表示為成功.... verifySignature.put("aliPayMentStatus", "1"); verifySignature.put("aliPayOrderNumber", "20190511"); // 解析報文是否成功 200 為成功.. verifySignature.put("analysisCode", PayConstant.RESULT_PAYCODE_200); return verifySignature; } @Override protected String asyncService(Map<String, String> verifySignatureMap) { log.info(">>>>>第三步asyncService()verifySignatureMap:{}", verifySignatureMap); String paymentStatus = verifySignatureMap.get("aliPayMentStatus"); if (paymentStatus.equals("1")) { String aliPayOrderNumber = verifySignatureMap.get("aliPayOrderNumber"); log.info(">>>>orderNumber:{aliPayOrderNumber},已經支付成功 修改訂單狀態為已經支付..."); } return resultSuccess(); } @Override protected String resultSuccess() { return PayConstant.ALIPAY_RESULT_SUCCESS; } @Override protected String resultFail() { return PayConstant.ALIPAY_RESULT_FAIL; } }
②UnionPayCallbackTemplate
/** * @title: UnionPayCallbackTemplate */ @Component @Slf4j public class UnionPayCallbackTemplate extends AbstractPayCallbackTemplate { @Override protected Map<String, String> verifySignature() { //>>>>銀聯回撥報文虛擬碼>>>>>>>> log.info(">>>>>第一步 解析銀聯資料報文.....verifySignature()"); Map<String, String> verifySignature = new HashMap<>(); verifySignature.put("price", "10000"); verifySignature.put("orderDes", "充值會員"); // 支付狀態為1表示為成功.... verifySignature.put("paymentStatus", "1"); verifySignature.put("orderNumber", "20190511"); // 解析報文是否成功 200 為成功.. verifySignature.put("analysisCode", PayConstant.RESULT_PAYCODE_200); return verifySignature; } @Override protected String asyncService(Map<String, String> verifySignatureMap) { log.info(">>>>>第三步asyncService()verifySignatureMap:{}", verifySignatureMap); String paymentStatus = verifySignatureMap.get("paymentStatus"); if (paymentStatus.equals(PayConstant.PAY_STATUS_SUCCESS)) { String orderNumber = verifySignatureMap.get("orderNumber"); log.info(">>>>orderNumber:{orderNumber},已經支付成功 修改訂單狀態為已經支付..."); } return resultSuccess(); } @Override protected String resultSuccess() { return PayConstant.UNION_RESULT_SUCCESS; } @Override protected String resultFail() { return PayConstant.UNION_RESULT_FAIL; } }
工廠模式獲取模版
/**
* @title: TemplateFactory
*/
public class TemplateFactory {
public static AbstractPayCallbackTemplate getPayCallbackTemplate(String templateId) {
AbstractPayCallbackTemplate payCallbackTemplate = (AbstractPayCallbackTemplate) SpringUtils.getBean(templateId);
return payCallbackTemplate;
}
}
SpringUtils
@Component
public class SpringUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
//獲取applicationContext
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
//通過name獲取 Bean.
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
//通過class獲取Bean.
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
//通過name,以及Clazz返回指定的Bean
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
}
相關依賴
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
</parent>
<dependencies>
<!-- sprinboot web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
Controller層
/**
* @title: TemplateController
*/
@RestController
public class TemplateController {
@RequestMapping("/asyncCallBack")
public String asyncCallBack(String templateId) {
AbstractPayCallbackTemplate payCallbackTemplate = TemplateFactory.getPayCallbackTemplate(templateId);
return payCallbackTemplate.asyncCallBack();
}
}
程式入口
@SpringBootApplication
@EnableAsync
public class AppTemplate {
public static void main(String[] args) {
SpringApplication.run(AppTemplate.class);
}
}
控制檯輸出結果
2019-05-11 23:23:30.420 INFO 27576 --- [nio-8080-exec-9] c.x.t.impl.AliPayCallbackTemplate : >>>>>第一步 解析支付寶據報文.....verifySignature()
2019-05-11 23:23:30.420 INFO 27576 --- [nio-8080-exec-9] c.x.t.AbstractPayCallbackTemplate : >>>>>>>>>>第二步 寫入payLog........{aliPayOrderNumber=20190511, orderDes=充值會員, price=10000, analysisCode=200, aliPayMentStatus=1}
2019-05-11 23:23:30.420 INFO 27576 --- [nio-8080-exec-9] c.x.t.impl.AliPayCallbackTemplate : >>>>>第三步asyncService()verifySignatureMap:{aliPayOrderNumber=20190511, orderDes=充值會員, price=10000, analysisCode=200, aliPayMentStatus=1}
2019-05-11 23:23:30.420 INFO 27576 --- [nio-8080-exec-9] c.x.t.impl.AliPayCallbackTemplate : >>>>orderNumber:{aliPayOrderNumber},已經支付成功 修改訂單狀態為已經支付...
2019-05-11 23:23:32.710 INFO 27576 --- [io-8080-exec-10] c.x.t.impl.UnionPayCallbackTemplate : >>>>>第一步 解析銀聯資料報文.....verifySignature()
2019-05-11 23:23:32.710 INFO 27576 --- [io-8080-exec-10] c.x.t.AbstractPayCallbackTemplate : >>>>>>>>>>第二步 寫入payLog........{orderNumber=20190511, orderDes=充值會員, price=10000, analysisCode=200, paymentStatus=1}
2019-05-11 23:23:32.710 INFO 27576 --- [io-8080-exec-10] c.x.t.impl.UnionPayCallbackTemplate : >>>>>第三步asyncService()verifySignatureMap:{orderNumber=20190511, orderDes=充值會員, price=10000, analysisCode=200, paymentStatus=1}
總結
模版設計模式優缺點
1.優點
模板方法模式通過把不變的行為搬移到超類,去除了子類中的重複程式碼。子類實現演算法的某些細節,有助於演算法的擴充套件。通過一個父類呼叫子類實現的操作,通過子類擴充套件增加新的行為,符合“開放-封閉原則”。
2.缺點
每個不同的實現都需要定義一個子類,這會導致類的個數的增加,設計更加抽象。
3.適用場景
在某些類的演算法中,用了相同的方法,造成程式碼的重複。控制子類擴充套件,子類必須遵守演算法規則。
工廠設計模式優缺點
優點:
1.程式碼結構簡單。
2.獲取產品的過程更加簡單。
3.滿足了開閉原則,即對拓展開放,對修改關閉。
缺點:
拓展較繁瑣,要拓展時,需同時改動抽象工廠和工廠實現類。
對比策略模式和責任鏈設計模式,請關注部落格——須臾之餘
——經典設計模式之策略模式【如何重構聚合支付平臺,對接【支付寶,微信,銀聯支付】】
——【奇思妙想】如何給閘道器設計一款專屬的許可權控制【責任鏈設計模式】