背景
介绍一个新写的小东西,叫FastConverter,叫这个名字是因为,它最初是被设计用来将服务器返回给前端的数据实体转换为json字符串的。
需求背景是:服务器经过一系列计算后,最终数据被存放在一个数据实体中,经过toJSON化,输出到前端。但输出时我们对数据有一些格式化,或自定制化的需求,比如,数据实体中的Date,最终输出可能是时间戳,也可能是“yyyy-MM-dd”;数据实体中的用以表示金额的BigDecimal,在服务器端我们用元做单位,带小数点,输出时我们想让它变成以分为单位,不带小数点;用户敏感信息打码(用户名,身份证号,手机号等)等等。总之就是,直接将数据实体toJSON,不能满足我们的需求,在toJSON的同时,我们需要对数据做一些转换。
设计思路
很多初学者设计一个工具的时候,思路很散,做出来的东西不成体系。比如上面所述的功能,有的人肯定是一个 "XxxTool"类 或者 "XxxUtils"类 就实现了。
但这种散件非常丑陋,类的抽象和类的接口息息相关, "XxxTool"类 或者 "XxxUtils"类最大的问题是,它无法有效且内聚的描述自己的抽象,它的接口大多数情况下各司其职,这样的类一定违背开闭原则,依赖倒转原则,也违背内聚性。实在点说就是:1,当客户端程序员去使用这些工具类时,他们会发现,这个类有好多方法;2,每个方法似乎都是一个独立的功能点;3,当他发现缺少他需要的功能时,他会不知所措,到底如何修改这个庞大的类;4,时间久了,这个类一定是无法维护的(这个复杂的私有方法是干什么的???为什么只为那个公共方法提供服务???这个私有域又是干什么的???我可以修改它吗???还有哪些地方使用了它???算了,我自己加个新的域来实现我的功能吧);5,会有很多类依赖(紧耦合)这个工具类。
如果你在开发系统底层的时候不在乎这些小问题,等系统变得庞杂起来时,它会让你寸步难行,这是很明显的弊端,但我很惊讶如此多的人对它视而不见(也许是因为教科书上不教这些小细节吧)。
第一步,接口开发
既然是转换数据,接口的设计挺自然的:
public interface Converter<T, K> {
K convert(T value, String tip) throws ConvertException;
K convert(T value) throws ConvertException;
boolean supports(T value);
}
supports这个方法的设计学习了spring框架,后续开发也证明,它非常有用。值得一提的是,supports方法接收的是一个对象,而不是Class<T>。我在开发的时候曾经将它修改为Class<T>过,但后来发现,这样做局限性很大,而且被转换对象一定是事先存在了的,此处不需要使用Class来做先于数据的判断;再者,如果是接收Class<T>,任何泛型T类型一致的转换器将无法共存(后续讲解)。
convert方法中有一个String类型的tip参数,它是用来赋予转换器一定灵活性而引入的。比如要将Date转换为 “yyyy-MM-dd” 和 “yyyy.MM.dd” 你只需要一个转换器就能实现。
抛出的异常:
public class ConvertException extends Exception {
public ConvertException(String message) {
super(message);
}
}
有了转换器,我们还需要一个转换器过滤器,因为在我的思路里,我们可以将多个转换器注册到一个容器中,让容器自动根据supports过滤出适合某种数据的转换器(后续你将看到,它非常有用)。
public interface ConverterFilter {
<T> Converter getConverter(T value);
}
由于泛型擦除机制的存在,该接口就算限定返回值是Converter<T, K> ,你也无法获取到正确的能将T -> K 的Converter<T, K>转换器,你获取到的仅仅是Converter。所以此处定义的返回值是Converter,而不是Converter<T, K>。
第二步,注解开发
我在需求中提到了,要将数据实体中的数据做一些格式化或自定制化的转换。实现这一步我采用的是默认转换加自定义转换并存的策略。自定义转换如何工作?使用注解!通过在域(类中声明的字段)上打上注解来告知系统,此域如何进行转换。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public [@interface](https://my.oschina.net/u/996807) FieldConverter {
String tip() default "";
Class<? extends Converter> converter();
}
这个注解很简单,就不赘述了。
第三步,注解消化器:
public class BeanToMapConverterHandler extends AbstractFilterBaseConverterHandler<Ob