一:场景与设计
1.1 实战场景
- 入参
参数过多
,需要进行多维度校验
如空值、范围值、格式等 - 校验规则
修改较频繁
1.2 设计思想
- 根据HTTP协议异常分类思想实现异常枚举、策略维度划分
- 门面将策略组装,屏蔽上层模块校验策略实现
二:优点
- 异常信息枚举+自定义异常有益于异常定位以及异常管理
- 策略抽象划分校验维度符合
单一职责原则
- 门面组装让上层模块屏蔽掉校验策略实现,符合
迪米特法则
- 最主要丢掉上层模块大批量出现if - else 判断,避免出现多次修改后出现的
重复校验、校验层次混乱
问题
三:缺点
- 代码量上升,可读性相对于直接使用if - else某些层面有所下降
- 现有检验规则修改还是不可避免需要修改检验策略类
四:代码实现
4.1 异常信息枚举
将异常编码与信息根据校验维度使用枚举类进行封装,统一管理异常
/**
* @EnumName: ParameterLenthEnum
* @Description 参数空值检验信息异常枚举
* @Author: zsl
* @Data: 2019/4/17 10:46
* @Version 1.0
**/
public enum ParameterNullValueEnum {
REQUEST_MESSAGE(5000,"请求报文空值异常"),
MESSAGE_HEAD(5001,"报文头空值异常"),
MESSAGE_BODY(5002,"报文体空值异常"),
VERSION(5003,"接口版本号空值异常"),
......
REQURL(5011,"接口请求地址空值异常");
private Integer code;
private String message;
private ParameterNullValueEnum(Integer _code, String _message){
this.code = _code;
this.message = _message;
}
......
/**
* @EnumName: ParameterLegalEnum
* @Description 参数合法校验异常枚举
* @Author: zsl
* @Data: 2019/4/17 13:16
* @Version 1.0
**/
public enum ParameterLegalEnum {
PROVINCE(5201,"省份编码属性值非法"),
SOURCE_CODE(5202,"数据来源编码属性值非法"),
MESTYPE(5203,"报文类型编码属性值非法");
private Integer code;
private String message;
private ParameterLegalEnum(Integer _code,String _message){
this.code = _code;
this.message = _message;
}
......
}
4.2 自定义异常类
使用异常信息枚举对象自定义异常类
/**
* @ClassName: ParameterNullValueException
* @Description 参数空值异常
* @Author: zsl
* @Data: 2019/4/17 10:16
* @Version 1.0
**/
public class ParameterNullValueException extends NullPointerException{
private ParameterNullValueEnum nve;
public ParameterNullValueException(ParameterNullValueEnum _nve){
this.nve = _nve;
}
public ParameterNullValueEnum getNve() {
return nve;
}
public void setNve(ParameterNullValueEnum nve) {
this.nve = nve;
}
@Override
public String getMessage() {
return "异常编码: "+this.nve.getCode() +" 异常信息:"+ this.nve.getMessage();
}
}
/**
* @ClassName: ParameterLegalException
* @Description 参数合法性异常
* @Author: zsl
* @Data: 2019/4/17 13:24
* @Version 1.0
**/
public class ParameterLegalException extends IllegalArgumentException{
private ParameterLegalEnum ple;
public ParameterLegalException(ParameterLegalEnum _ple){
this.ple = _ple;
}
public ParameterLegalEnum getPle() {
return ple;
}
public void setPle(ParameterLegalEnum ple) {
this.ple = ple;
}
@Override
public String getMessage() {
return "异常编码: "+this.ple.getCode() +" 异常信息:"+ this.ple.getMessage();
}
}
4.3 策略抽象封装
封装维度根据入参、返回值下的空值校验、异常非法值校验等几方面
/**
* @InterfaceName: CheckStrategy
* @Description 校验策略
* @Author: zsl
* @Data: 2019/4/17 10:08
* @Version 1.0
**/
public interface CheckStrategy {
void checkMethod() throws ParameterNullValueException, ParameterLegalException;
}
/**
* @ClassName: AbstractParameterCheck
* @Description 参数检验抽象
* @Author: zsl
* @Data: 2019/4/17 11:09
* @Version 1.0
**/
public abstract class AbstractCheck implements CheckStrategy{
private RequestMessage rm;
protected RequestMessage getRm() {
return rm;
}
public void setRm(RequestMessage rm) {
this.rm = rm;
}
}
/**
* @ClassName: ParameterCheckStrategy
* @Description 参数校验空值策略
* @Author: zsl
* @Data: 2019/4/17 10:13
* @Version 1.0
**/
public class ParameterNullCheckStrategy extends AbstractCheck {
@Override
public void checkMethod() throws ParameterNullValueException {
// 对象空值检验
RequestMessage rm = this.getRm();
if (rm == null)
throw new ParameterNullValueException(ParameterNullValueEnum.REQUEST_MESSAGE);
......
}
}
/**
* @ClassName: ParameterLegalCheckStrategy
* @Description 参数合法校验策略
* @Author: zsl
* @Data: 2019/4/17 13:14
* @Version 1.0
**/
public class ParameterLegalCheckStrategy extends AbstractCheck {
@Override
public void checkMethod() throws ParameterLegalException {
RequestMessage rm = this.getRm();
MessageHead mh = rm.getMh();
// 省份编码合法校验
if (ProvinceEnum.valueOf(mh.getProvince()) == null)
throw new ParameterLegalException(ParameterLegalEnum.PROVINCE);
......
// 渠道来源编码有效监测
Integer sourceCode = mh.getSourceCode();
if(!(99 < sourceCode && sourceCode < 111)
|| (119 < sourceCode && sourceCode < 125)
|| (129 < sourceCode && sourceCode < 134)
|| (199 < sourceCode && sourceCode < 208)
|| (219 < sourceCode && sourceCode < 224)
|| (229 < sourceCode && sourceCode < 235)
|| (sourceCode == 999))
throw new ParameterLegalException(ParameterLegalEnum.SOURCE_CODE);
}
}
4.4 门面组装
屏蔽上层模块校验策略实现,使用枚举单例组装校验门面
package com.aisino.enums;
import com.aisino.strategy.AbstractCheck;
import com.aisino.strategy.ParameterLegalCheckStrategy;
import com.aisino.strategy.ParameterNullCheckStrategy;
/**
* @EnumName: CheckStrategyEnum
* @Description TODO 封装检验策略枚举
* @author: zsl
* @Data: 2019/5/9 8:53
* @Version 1.0
**/
public enum CheckStrategyEnum {
/**
* 校验空值枚举对象
*/
CHECK_NULL("空值校验",new ParameterNullCheckStrategy()),
/**
* 校验异常值枚举对象
*/
CHECK_LEGAL("异常值校验",new ParameterLegalCheckStrategy());
/**
* 校验策略实现子类对象
*/
private AbstractCheck ac;
/**
* 对象描述
*/
private String description;
private CheckStrategyEnum(String description,AbstractCheck ac){
this.ac = ac;
this.description = description;
}
public AbstractCheck getAc () {
return ac;
}
public void setAc (AbstractCheck ac) {
this.ac = ac;
}
public String getDescription () {
return description;
}
public void setDescription (String description) {
this.description = description;
}
}
4.5 调用层
/**
* 使用校验枚举对象进行参数校验
*@author zsl
*@data 2019/5/9 9:08
*@return void
**/
private void checkNullAndLegal(){
CheckStrategyEnum[] checks = CheckStrategyEnum.values();
for (CheckStrategyEnum cse : checks){
AbstractCheck ac = cse.getAc();
ac.setRm(this.rm);
ac.checkMethod();
}
}