记一个小小的转换工具的开发:FastConverter

FastConverter是一个用于将服务器数据实体转换为JSON字符串的工具,满足自定义转换需求,如日期格式化、金额单位转换等。设计上遵循开闭原则和高内聚性,包括接口开发、注解开发、注解消化器、ConverterFilter和多个转换器的实现。通过ConverterFilter,可以组合多个转换器处理复杂的数据转换,实现可插拔机制。
摘要由CSDN通过智能技术生成

背景

介绍一个新写的小东西,叫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
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值