前言
这篇文章的业务背景是基于我的另一篇文章:
对接苹果支付退款退单接口-CSDN博客
然后就是说设计模式是很开放的东西,可能我觉得合适,你可能觉得不合适,这里只是做下讨论,没有一定要各位同意的意思....
相关图文件
这里我先把相关的图文件放上来,可能看着会比较清晰点
代码逻辑
先把每个类的代码放上来一下,首先是接口
涉及java类
AppNotifyCommand(这个没啥好说的)
public interface AppNotifyCommand<T extends AppStoreNotifyDto> {
//命令定义,可以参考官网
//https://developer.apple.com/documentation/appstoreservernotifications/notification_type
String REFUND_COMMAND_NAME = "REFUND";
String NOT_FOUND_COMMAND_NAME = "NOT_FOUND";
/**
* 获取命令名称
* @return
*/
String getCommandName();
/**
* 执行命令
* @param T
*/
String execute(T T);
}
AbstractAppNotifyCommand(抽象类,给子类继承的,还是比较有意义的)
@Slf4j
public abstract class AbstractAppNotifyCommand<T extends AppStoreNotifyDto> implements AppNotifyCommand<T>{
@Override
public String getCommandName() {
String commandName = doGetCommandName();
if(StringUtil.isBlank(commandName)) {
throw new IllegalArgumentException("commandName为空");
}
return commandName;
}
@Override
public String execute(T T) {
try {
return doExecute(T);
} catch (Exception e) {
log.error("执行具体命令时发生异常", e);
throw new AppException("执行具体命令时发生异常", e);
}
}
protected abstract String doGetCommandName();
protected abstract String doExecute(T T) throws Exception;
}
AppRefundCommand(退款处理类)
@Service
public class AppRefundCommand extends AbstractAppNotifyCommand<AppStoreNotifyDto> {
@Override
protected String doGetCommandName() {
return REFUND_COMMAND_NAME;
}
@Override
protected String doExecute(AppStoreNotifyDto appStoreNotifyDto) throws Exception{
// //获取解密数据
// AppStoreDecodedPayloadDto appStoreDecodedPayloadDto = parseTransactionInfo(appStoreNotifyDto);
//
// //退款逻辑处理.....
return "执行完成了";
}
}
AppNotFoundCommand(找不到对应的处理命令时也写了一个处理类)
@Slf4j
@Service
public class AppNotFoundCommand extends AbstractAppNotifyCommand<AppStoreNotifyDto> {
@Override
protected String doGetCommandName() {
return NOT_FOUND_COMMAND_NAME;
}
@Override
protected String doExecute(AppStoreNotifyDto appStoreNotifyDto) throws Exception {
log.info("目前{}的命令没有进行处理,返回空字符串", appStoreNotifyDto.getNotificationType());
return "";
}
}
上面的几个类都是基础类,没啥好说的,主要是下面这个类,维护了对外的接口,如下
@Service
@Slf4j
public class AppCommandComposite {
@Resource
private List<AppNotifyCommand<AppStoreNotifyDto>> appNotifyCommandList;
private Map<String, AppNotifyCommand<AppStoreNotifyDto>> appNotifyCommandMap;
@PostConstruct
public void init() {
appNotifyCommandMap = new ConcurrentHashMap<>();
//循环放置数据
for (AppNotifyCommand<AppStoreNotifyDto> appNotifyCommand : appNotifyCommandList) {
appNotifyCommandMap.put(appNotifyCommand.getCommandName(), appNotifyCommand);
}
}
/**
* 执行命令
* @param appStoreNotifyPayLoadDto
* @return
*/
public String handleCommand(AppStoreNotifyPayLoadDto appStoreNotifyPayLoadDto) {
try {
//解密基础数据
AppStoreNotifyDto appStoreNotifyDto = AppStoreReturnUtil.verifyAndGet(appStoreNotifyPayLoadDto.getSignedPayload());
log.info("开始执行苹果的{}通知命令", appStoreNotifyDto.getNotificationType());
//获取安全的执行器执行
AppNotifyCommand<AppStoreNotifyDto> appNotifyCommand = appNotifyCommandMap.get(appStoreNotifyDto.getNotificationType());
String result = safeAppNotifyCommand(appNotifyCommand).execute(appStoreNotifyDto);
log.info("执行苹果的{}通知命令完成,返回的数据为{}", appStoreNotifyDto.getNotificationType(), result);
return result;
} catch (Exception e) {
log.error("解析苹果加密数据失败", e);
throw new AppException("解析苹果加密数据失败");
}
}
//获取安全的执行器执行
private AppNotifyCommand<AppStoreNotifyDto> safeAppNotifyCommand(AppNotifyCommand<AppStoreNotifyDto> appNotifyCommand) {
if(appNotifyCommand == null) {
return appNotifyCommandMap.get(AppNotifyCommand.NOT_FOUND_COMMAND_NAME);
}
return appNotifyCommand;
}
}
设计亮点
主要在AppCommandComposite类上面,主要用到了如下的一些亮点设计
1. 基于Spring 容器功能收集 以下数据
@Resource
private List<AppNotifyCommand<AppStoreNotifyDto>> appNotifyCommandList;
2. 基于Spring Bean的生命周期初始化方法 @PostConstruct 收集到map里面去
private Map<String, AppNotifyCommand<AppStoreNotifyDto>> appNotifyCommandMap;
3. 对外提供handleCommand 方法, 逻辑如下
首先对数据进行解密, 这在另外一篇文章说了,这里就不赘述了
其次根据苹果返回的notificationType获取到具体的命令处理器
精华在于,获取不到的时候会返回AppNotFoundCommand进行处理,而我们可以打印日志,表明苹果发了哪些请求,到时如果需要处理可以添加AppNotifyCommand实现类处理即可
结语
总的来说逻辑并不复杂,至于这样设计好不好每个人的看法就当不一样了,我个人是觉得这样的话可以统一很多逻辑,不需要后续的人员再参与,
不好的地方在于没有专门研究过设计模式的人可能看起来会很复杂,但是只要写好对应的文档其实就可了