源码地址:支付设计模式优化
背景
在我们开发中支付功能可能遇到的不少,今天这个案例就是以支付为中心,通过结合设计模式实现支付功能的扩展性。方便我们以后需求增加、变更的时候是我们开发起来得心应手,同时也减少QA的回归时间。
设计关系图
实现类
接口基类
/**
* @ClassName IPay
* @Description 支付接口
* @Author xiaowu
* @Date 2021/8/10 6:02 下午
*/
public interface IPayStrategy<T> {
/**
* 支付
* @param payBusiness
* @return
* @throws Exception
*/
Result pay(PayBusiness<T> payBusiness) throws Exception;
Logger logger = Logger.getLogger(IPayStrategy.class.getName());
}
策略控制类
/**
*
* @ClassName ContextHandler
* @Description: 策略控制
* @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);
}
}
工厂类
通过init 方法加载实现类的class 路径,注册实现到本地缓冲中,方便策略控制类获取具体实现类对象。
/**
* @ClassName PayStrategyFactory
* @Description: 支付策略工厂类
* @Author 小五
* @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));
}
}
支付方式枚举
/**
* @ClassName PayEnum
* @Description 支付方式枚举
* @Author drj
* @Date 2021/8/11 2:14 下午
*/
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;
}
}
支付实现类(aliPay)
这里只写模拟阿里支付宝实现类,其他类似
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("阿里云");
payBusiness.setBody(aliPayRequest);
IPayStrategy.logger.info("Ali Pay 请求参数: " + JSON.toJSONString(payBusiness));
Result<AliPayResponse> responseResult = new Result<>();
responseResult.setResultCode(200);
responseResult.setResultMsg("调用成功!");
AliPayResponse aliPayResponse = new AliPayResponse();
aliPayResponse.setAliPayResult("aliPay 接口调用成功 等待回调");
responseResult.setResultData(aliPayResponse);
return responseResult;
}
}
服务调用
/**
* @ClassName PayBusiness
* @Description: TODO
* @Author drj
* @Date 2021/8/10
* @Version V1.0
**/
public class PayBusiness<T> {
/**
* 支付金額
*/
private BigDecimal payAccount;
/**
* 支付方式
*/
private String payName;
/**
* 支付方式code
*/
private String payCode;
/**
* 不同支付方式业务参数
*/
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);
}
}
从上面服务调用可以发现我们只需要传入请求参数两行代码实现service 层的调用。后面我们假如有新需求增加其他支付方式,比如:qq、wx 只需要增加枚举和对应的实现类,即可 很容易得到扩展。
请求参数和返回参数分别都使用泛型接受可变对象,使得我们更加灵活。
测试
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("微信");
Result pay = payService.pay(payBusiness);
System.out.printf("支付接口返回参数:" + JSON.toJSONString(pay));
}
@Test
public void testAliPay() throws Exception {
PayBusiness payBusiness = new PayBusiness();
payBusiness.setPayAccount(new BigDecimal(200));
payBusiness.setPayCode("ali");
payBusiness.setPayName("阿里");
Result pay = payService.pay(payBusiness);
System.out.printf("支付接口返回参数:" + JSON.toJSONString(pay));
}
@Test
public void testPay() throws Exception {
PayBusiness payBusiness = new PayBusiness();
payBusiness.setPayAccount(new BigDecimal(200));
payBusiness.setPayCode("qq");
payBusiness.setPayName("qq 钱包");
Result payQq = payService.pay(payBusiness);
System.out.println("支付接口返回参数:" + JSON.toJSONString(payQq));
payBusiness.setPayCode("wx");
payBusiness.setPayName("wx 支付");
Result<WxPayResponse> payWx = payService.pay(payBusiness);
System.out.println("支付接口返回参数:" + JSON.toJSONString(payWx));
payBusiness.setPayCode("ali");
payBusiness.setPayName("ali 支付");
Result<AliPayResponse> payAli = payService.pay(payBusiness);
System.out.println("支付接口返回参数:" + JSON.toJSONString(payAli));
}
九月 28, 2021 11:42:59 下午 com.bj.drj.design01.factory.impl.QqPay pay
信息: QPay 请求参数: {“body”:{“qq”:“qq”},“payAccount”:200,“payCode”:“qq”,“payName”:“qq 钱包”}
九月 28, 2021 11:42:59 下午 com.bj.drj.design01.factory.impl.QqPay pay
信息: 调用qq支付
支付接口返回参数:{“resultCode”:200,“resultData”:{“qqPayResult”:“qqPay 接口调用成功 等待回调”},“resultMsg”:“调用成功!”}
支付接口返回参数:{“resultCode”:200,“resultData”:{“wxPayResult”:“wx Pay 接口调用成功, 等待回调”},“resultMsg”:“调用成功!”}
九月 28, 2021 11:42:59 下午 com.bj.drj.design01.factory.impl.WxPay pay
支付接口返回参数:{“resultCode”:200,“resultData”:{“aliPayResult”:“aliPay 接口调用成功 等待回调”},“resultMsg”:“调用成功!”}
信息: Wx Pay 请求参数: {“body”:{“wx”:“微信”},“payAccount”:200,“payCode”:“wx”,“payName”:“wx 支付”}
九月 28, 2021 11:42:59 下午 com.bj.drj.design01.factory.impl.AliPay pay
信息: Ali Pay 请求参数: {“body”:{“ali”:“阿里云”},“payAccount”:200,“payCode”:“ali”,“payName”:“ali 支付”}