background
Payment function may encounter a lot in our development. Today this case is centered on payment to achieve the extensibility of payment function through the combination of design mode. It will be convenient for us to develop when demand increases and changes in the future, and it will also reduce the return time of QA.
Design Diagram
Implementation Class
Interface Base Class
/** * @ClassName IPay * @Description Payment interface * @Author xiaowu * @Date 2021/8/10 6:02 Afternoon */ public interface IPayStrategy<T> { /** * payment * @param payBusiness * @return * @throws Exception */ Result pay(PayBusiness<T> payBusiness) throws Exception; Logger logger = Logger.getLogger(IPayStrategy.class.getName()); }
Policy Control Class
/** * * @ClassName ContextHandler * @Description: Policy Control * @Author xiaowu * @Date 2021/8/10 * @Version V1.0 **/ public class ContextStrategy<T> { private IPayStrategy<T> pay; public ContextStrategy(IPayStrategy<T> pay) { this.pay = pay; } public Result payProcess(PayBusiness<T> t) throws Exception { return pay.pay(t); } }
Factory Class
The init method loads the class path of the implementation class, registers the implementation in the local buffer, and facilitates the policy control class to obtain the specific implementation class object.
/** * @ClassName PayStrategyFactory * @Description: Payment Policy Factory Class * @Author Small Five * @Date 2021/8/10 * @Version V1.0 **/ public class PayStrategyFactory { private Logger logger = Logger.getLogger(PayFactoryInstance.class); private static Map<String, IPayStrategy> registerServices = new ConcurrentHashMap<String, IPayStrategy>(); private PayStrategyFactory() { init(); } public static PayStrategyFactory getInstance() { return PayFactoryInstance.instance; } private static class PayFactoryInstance { private static PayStrategyFactory instance = new PayStrategyFactory(); } private void init() { Set<Class<?>> classes = ClassScanner.scanPackage("com.bj.drj.design01.factory.impl"); classes.stream().forEach(x -> registerService(x)); } private void registerService(Class registerClass) { try { registerServices.put(registerClass.getName(), (IPayStrategy) registerClass.newInstance()); } catch (Exception e) { logger.error(e); } } public IPayStrategy getPayService(String payCode) { return registerServices.get(PayEnum.getClassPath(payCode)); } }
Payment Method Enumeration
/** * @ClassName PayEnum * @Description Payment Method Enumeration * @Author drj * @Date 2021/8/11 2:14 Afternoon */ public enum PayEnum { ALI_PAY("ali", "com.bj.drj.design01.factory.impl.AliPay"), QQ_PAY("qq", "com.bj.drj.design01.factory.impl.QqPay"), WX_PAY("wx", "com.bj.drj.design01.factory.impl.WxPay"); private String payCode; private String payClassPath; public String getPayCode() { return payCode; } public String getPayClassPath() { return payClassPath; } PayEnum(String payCode, String payClassPath) { this.payCode = payCode; this.payClassPath = payClassPath; } public static String getClassPath(String payCode) { for (PayEnum payEnum : values()) { if (Objects.equals(payEnum.getPayCode(), payCode)) { return payEnum.getPayClassPath(); } } return null; } }
Payment implementation class (aliPay)
Here only simulate Alibaba implementation class, other similar
public class AliPay implements IPayStrategy<AliPayRequest> { /** * @param payBusiness * @return * @throws Exception */ @Override public Result<AliPayResponse> pay(PayBusiness<AliPayRequest> payBusiness) throws Exception { AliPayRequest aliPayRequest = new AliPayRequest(); aliPayRequest.setAli("Ali Yun"); payBusiness.setBody(aliPayRequest); IPayStrategy.logger.info("Ali Pay Request parameters: " + JSON.toJSONString(payBusiness)); Result<AliPayResponse> responseResult = new Result<>(); responseResult.setResultCode(200); responseResult.setResultMsg("Call succeeded!"); AliPayResponse aliPayResponse = new AliPayResponse(); aliPayResponse.setAliPayResult("aliPay Interface call succeeded waiting for callback"); responseResult.setResultData(aliPayResponse); return responseResult; } }
Service Calls
/** * @ClassName PayBusiness * @Description: TODO * @Author drj * @Date 2021/8/10 * @Version V1.0 **/ public class PayBusiness<T> { /** * Payment amount */ private BigDecimal payAccount; /** * Payment method */ private String payName; /** * Payment Method code */ private String payCode; /** * Business parameters for different modes of payment */ private T body; public BigDecimal getPayAccount() { return payAccount; } public void setPayAccount(BigDecimal payAccount) { this.payAccount = payAccount; } public String getPayName() { return payName; } public void setPayName(String payName) { this.payName = payName; } public T getBody() { return body; } public void setBody(T body) { this.body = body; } public String getPayCode() { return payCode; } public void setPayCode(String payCode) { this.payCode = payCode; } }
public class PayService { public Result pay(PayBusiness payBusiness) throws Exception { ContextStrategy contextHandler = new ContextStrategy(PayStrategyFactory.getInstance().getPayService(payBusiness.getPayCode())); return contextHandler.payProcess(payBusiness); } }
From the above service calls, you can see that we only need two lines of code to pass in the request parameter to implement the service layer call. Later, we can easily expand if there are new requirements to increase other payment methods, such as qq, wx, simply by adding enumerations and corresponding implementation classes.
Request and return parameters use generics to accept mutable objects, respectively, to make us more flexible.
test
public class PayTest { @Inject private PayService payService; @Inject private PayDemo payDemo; @Before public void init() { CommonInjector.getInjector().injectMembers(this); } @Test public void testWxPay() throws Exception { PayBusiness payBusiness = new PayBusiness(); payBusiness.setPayAccount(new BigDecimal(200)); payBusiness.setPayCode("wx"); payBusiness.setPayName("WeChat"); Result pay = payService.pay(payBusiness); System.out.printf("Payment interface return parameters:" + JSON.toJSONString(pay)); } @Test public void testAliPay() throws Exception { PayBusiness payBusiness = new PayBusiness(); payBusiness.setPayAccount(new BigDecimal(200)); payBusiness.setPayCode("ali"); payBusiness.setPayName("Ali"); Result pay = payService.pay(payBusiness); System.out.printf("Payment interface return parameters:" + JSON.toJSONString(pay)); } @Test public void testPay() throws Exception { PayBusiness payBusiness = new PayBusiness(); payBusiness.setPayAccount(new BigDecimal(200)); payBusiness.setPayCode("qq"); payBusiness.setPayName("qq wallet"); Result payQq = payService.pay(payBusiness); System.out.println("Payment interface return parameters:" + JSON.toJSONString(payQq)); payBusiness.setPayCode("wx"); payBusiness.setPayName("wx payment"); Result<WxPayResponse> payWx = payService.pay(payBusiness); System.out.println("Payment interface return parameters:" + JSON.toJSONString(payWx)); payBusiness.setPayCode("ali"); payBusiness.setPayName("ali payment"); Result<AliPayResponse> payAli = payService.pay(payBusiness); System.out.println("Payment interface return parameters:" + JSON.toJSONString(payAli)); }
September 28, 2021 11:42:59 PM com.bj.drj.design01.factory.impl.QqPay pay
Information: QPay request parameters: {"body": {"qq": "qqq"}, "payAccount": 200, "payCode": "qqq", "payName": "qqq wallet"}
September 28, 2021 11:42:59 PM com.bj.drj.design01.factory.impl.QqPay pay
Information: Call qq payment
Payment interface return parameters: {"resultCode": 200, "resultData": {"qqPayResult": "qqPay interface call successfully awaits callback"}, "resultMsg": "call successfully!"}
Payment interface return parameters: {"resultCode": 200, "resultData": {"wxPayResult": "wx Pay interface call succeeded, waiting for callback"}, "resultMsg": "call succeeded!"}
September 28, 2021 11:42:59 PM com.bj.drj.design01.factory.impl.WxPay pay
Payment interface return parameters: {"resultCode": 200, "resultData": {"aliPayResult": "aliPay interface call successfully awaits callback"}, "resultMsg": "call successfully!"}
Information: Wx Pay request parameters: {"body": {"wx": "WeChat"}, "payAccount": 200, "payCode": "wx", "payName": "wx payment"}
September 28, 2021 11:42:59 PM com.bj.drj.design01.factory.impl.AliPay pay
Information: Ali Pay request parameters: {"body": {"ali": "Ali cloud"}, "payAccount": 200, "payCode": "ali", "payName": "ali payment"}