
业务需求

前一篇文章《矩阵的转置及在关系型数据库中的实践》中介绍了一种k-v存储的数据表结构(即AT表),这种数据表的应用场景为自定义业务对象。在该业务场景中,有一个需求是这样的:
在数据插入操作中,针对前端传过来的属性值,
如果该属性配置了自动生成功能,则调用自动生成逻辑生成一个值替换前端传递的值进行存储,如订单号;
否则,如果该属性值不为空,则将该属性值进行存储,如客户姓名;
否则,如果该属性配置了默认值,则将配置的默认值作为该属性的值进行存储,如是否有效;
否则,不进行任何处理。
上边的业务逻辑可以作为赋值操作进行统一封装,我们先看下常规操作代码是如何处理的。

常规操作模式

常规操作模式,即通过if…else…逻辑块进行处理,其代码示例如下所示。
// ① 调用自动生成方法,如果返回null表示非自动生成属性
Object value = DataProcess.getInstance().getDefaultValue(cfgFormField);
if (value == null){
// ② 取前端传入值
if (jsonParam.containsKey(fieldCode)
&& StringUtils.isNotBlank(jsonParam.getString(fieldCode))) {
value = jsonParam.get(fieldCode);
// ③ 前端未传值,取默认值
} else if (StrUtil.isNotBlank(cfgFormField.getDefaultValue())) { // 无前端传入,但有默认值
value = cfgFormField.getDefaultValue();
// ④ 既无前端传入值,也无默认值,则不处理
} else {
return;
}
}
复制
在这个示例中,通过if…else…实现了上述逻辑,如果有新业务逻辑的加入,则继续if…else…块的编写。考虑到代码的后期维护,显然这种实现方式是不符合要求的,违背了软件设计的开闭原则。那么就需要对这段代码进行改造,责任链模式是一个不错的选择。

责任链模式

上述代码的业务逻辑,说白了就是对value进行赋值,或者说清理,那么可以创建一个统一的值清理类DataValueCleaner,并定义一个静态方法clean,返回值为清理后的最终结果。
因为动态属性的赋值方案都封装在cfgFormField对象中,所以clean方法需要接受cfgFormField和前端传值。
DataValueCleaner类的实现如下所示。
public class DataValueCleaner {
/**
* 值清洗方法
* @param formField
* @param value
* @return
*/
public static Object clean(CfgFormField formField, Object value) {
// TODO 数据处理逻辑
}
}
复制
接下来定义数据处理的统一接口ValueProcessor,该接口只有一个方法process,接收value入参,返回Object对象,该对象及经过处理后的value值。其实现如下所示。
public interface ValueProcessor {
/**
* 值处理方法
* @param formField
* @param value
* @return
*/
Object process(CfgFormField formField, Object value);
}
复制
该接口有三个实现类,AutoGenerateValueProcessor用于处理自动生成逻辑,OriginalValueProcessor用于原值处理,DefaultValueProcessor用于默认值处理。这三个实现类的具体逻辑与上述的① ② ③相同,此处不再赘述。至此,DataValueCleaner就可以细化代码逻辑进行责任链的封装,其具体实现如下所示。
public class DataValueCleaner {
/**
* 值处理链
*/
private static List<ValueProcessor> processorChain = new ArrayList<>();
static {
processorChain.add(new AutoGenerateValueProcessor());
processorChain.add(new OriginalValueProcessor());
processorChain.add(new DefaultValueProcessor());
}
/**
* 值清洗方法
* @param formField
* @param value
* @return
*/
public static Object clean(CfgFormField formField, Object value) {
Object result = value;
for (ValueProcessor processor : processorChain) {
result = processor.process(formField, result);
}
return result;
}
}
复制
clean()方法中,通过循环来保证责任链中的每个处理逻辑都能够被执行到,如果某一个节点无处理逻辑,只需将value值return即可。在调用处,将上述的大段if…else…代码替换为如下一行语句,是不是更简洁了?
Object value = DataValueCleaner.clean(cfgFormField, jsonParam.get(fieldCode));
复制

业务逻辑扩展

如果在业务开发过程中,新增了业务逻辑,比如将时间属性的字段进行时间戳转换,那又该如何处理呢。
第一步,新建时间格式转换类,实现ValueProcessor接口并在process方法中编写业务逻辑;
第二步,在DataValueCleaner的责任链对象processorChain中添加第一步定义的类实例。
至此完成了业务逻辑的改造,通过责任链模式简化了代码结构、解耦了业务处理逻辑并提高了扩展性。