ConverterFactory
从名称上看它代表一个转换工厂:可以将对象S转换为R的所有子类型,从而形成1:N的关系。
该接口描述为xxxFactory是非常合适的,很好的表达了1:N的关系
public interface ConverterFactory<S, R> { <T extends R> Converter<S, T> getConverter(Class<T> targetType); }
它同样也是个函数式接口。该接口的实现类并不多,Spring Framework共提供了5个内建实现(访问权限全部为default):
以StringToNumberConverterFactory为例看看实现的套路:
final class StringToNumberConverterFactory implements ConverterFactory<String, Number> { @Override public <T extends Number> Converter<String, T> getConverter(Class<T> targetType) { return new StringToNumber<T>(targetType); } // 私有内部类:实现Converter接口。用泛型边界约束一类类型 private static final class StringToNumber<T extends Number> implements Converter<String, T> { private final Class<T> targetType; public StringToNumber(Class<T> targetType) { this.targetType = targetType; } @Override public T convert(String source) { if (source.isEmpty()) { return null; } return NumberUtils.parseNumber(source, this.targetType); } } }
由点知面,ConverterFactory作为Converter的工厂,对Converter进行包装,从而达到屏蔽内部实现的目的,对使用者友好,这不正是工厂模式的优点么,符合xxxFactory的语义。但你需要清除的是,工厂内部实现其实也是通过众多if else之类的去完成的,本质上并无差异。
代码示例
/** * ConverterFactory:1:N */ @Test public void test2() { System.out.println("----------------StringToNumberConverterFactory---------------"); ConverterFactory<String, Number> converterFactory = new StringToNumberConverterFactory(); // 注意:这里不能写基本数据类型。如int.class将抛错 System.out.println(converterFactory.getConverter(Integer.class).convert("1").getClass()); System.out.println(converterFactory.getConverter(Double.class).convert("1.1").getClass()); System.out.println(converterFactory.getConverter(Byte.class).convert("0x11").getClass()); }
运行程序,正常输出:
----------------StringToNumberConverterFactory--------------- class java.lang.Integer class java.lang.Double class java.lang.Byte
关注点:数字类型的字符串,是可以被转换为任意Java中的数字类型的,String(1) -> Number(N)。这便就是ConverterFactory的功劳,它能处理这一类转换问题。
不足
既然有了1:1、1:N,自然就有N:N。比如集合转换、数组转换、Map到Map的转换等等,这些N:N的场景,就需要借助下一个接口GenericConverter来实现。
GenericConverter
它是一个通用的转换接口,用于在两个或多个类型之间进行转换。相较于前两个,这是最灵活的SPI转换器接口,但也是最复杂的。
public interface GenericConverter { Set<ConvertiblePair> getConvertibleTypes(); Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType); // 普通POJO final class ConvertiblePair { private final Class<?> sourceType; private final Class<?> targetType; } }
该接口并非函数式接口,虽然方法不多但稍显复杂。现对出现的几个类型做简单介绍:
- ConvertiblePair:维护sourceType和targetType的POJO
- getConvertibleTypes()方法返回此Pair的Set集合。由此也能看出该转换器是可以支持N:N的(大多数情况下只写一对值而已,也有写多对的)
- TypeDescriptor:类型描述。该类专用于Spring的类型转换场景,用于描述from or to的类型
- 比单独的Type类型强大,内部借助了ResolvableType来解决泛型议题
GenericConverter的内置实现也比较多,部分截图如下:
ConditionalGenericConverter是GenericConverter和条件接口ConditionalConverter的组合,作用是在执行GenericConverter转换时增加一个前置条件判断方法。
说明:分割线下面的4个转换器比较特殊,字面上不好理解其实际作用,比较“高级”。它们如果能被运用在日常工作中可以事半功弎,因此放在在下篇文章专门给你介绍