问题
接了一个需求,从数据库拿出患者的记录,这些记录都是一些吸烟年份、饮酒年份、是否糖尿病等,不是数字就是布尔值,需要通过代码转化为普通人能理解的文字。
思前想后,总不能使用大量 if-else
判断来拼接字符串吧。可以采用模板,但是那样除了必要判空,代码和模板也将分离,不方便维护。而且有些字段存在依赖关系。
解决
刚好之前看了使用注解来替代枚举的方式。想着是否可以在每个需要拼接的字段上打上注解,通过判断注解的方式拼接。注解中也可以放入模板、依赖关系等配置。
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface StringAssemble {
/**
* 模板
*/
String template();
/**
* 分类
*/
String type() default "";
/**
* 上级依赖
*/
String dependency() default "";
/**
* 相互依赖的内容之间的分割符号
*/
String dependencySplit() default ",";
}
上面注解中,templete
主要是字段值需要填入的文字模板,type
用于不同的字段组合,dependency
主要是有依赖关系的字段之间的内容组合,最后一个是有依赖关系的字段字段拼接后用于隔离的标点。
实现代码如下:
private static String stringAssemble(Object data, String type, String splitPunctuation) {
final Map<String, String> infoMap = new HashMap<>();
final Map<String, String> dependencyMap = new HashMap<>();
try {
Field[] fields = data.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(StringAssemble.class)) {
StringAssemble stringAssemble = field.getAnnotation(StringAssemble.class);
if (type == null || stringAssemble.type().equals(type)) {
field.setAccessible(true);
Object o = field.get(data);
if (o != null) {
if (stringAssemble.dependency() != null && !"".equals(stringAssemble.dependency())) {
String info = stringAssemble.dependencySplit() + String.format(stringAssemble.template(), o.toString());
if (dependencyMap.containsKey(stringAssemble.dependency())) {
info = dependencyMap.get(stringAssemble.dependency()) + info;
}
dependencyMap.put(stringAssemble.dependency(), info);
} else {
infoMap.put(field.getName(), String.format(stringAssemble.template(), o.toString()));
}
}
}
}
}
dependencyMap.keySet().stream().filter(x -> infoMap.containsKey(x)).forEach(x -> infoMap.put(x, infoMap.get(x) + dependencyMap.get(x)));
} catch (Exception e) {
LOG.error("拼接字符串错误:Object:{}, e:{}", data, e);
e.printStackTrace();
}
这个代码实现按注解套用模板,处理一级依赖关系,自定义拼接使用的标点。需要待完善的字段组合时候没有顺序、无法处理两级或以上的依赖关系。
相比 if-else
,这个代码能大大简化工作,只要这部分代码不出问题,能保证所有的拼接都正确,减少bug引入。当然这个仅能处理简单的字段转文字并拼接的需要。格式过于复制就无法使用。代码尚不完善,仅供参考。这个方案似乎也并完美,如果有更好的方案,欢迎留言。