【问题标题】:Implementation for object converter design pattern using generics使用泛型实现对象转换器设计模式
【发布时间】:2019-08-26 21:34:48
【问题描述】:

我正在尝试为我的 dto 实体类创建一个通用对象转换器。我创建了一个抽象类,其中包含两个代表两种转换的函数,然后在我的具体转换器类中对其进行了扩展。

但是我想要一个通用的转换服务,我可以在启动期间注册我所有的转换器,然后方便地调用一个方法来处理彼此之间的转换。

这是我迄今为止提出的:

转换器抽象类

public abstract class Converter<D, E> {

  private final Function<D, E> fromFirstToSecond;
  private final Function<E, D> fromSecondToFirst;

  public Converter(final Function<D, E> fromFirstToSecond, final Function<E, D> fromSecondToFirst) {
    this.fromFirstToSecond = fromFirstToSecond;
    this.fromSecondToFirst = fromSecondToFirst;
  }

  public final E convertFromFirstToSecond(final D first) {
    return fromFirstToSecond.apply(first);
  }

  public final D convertFromSecondToFirst(final E second) {
    return fromSecondToFirst.apply(second);
  }

}

转换器具体类

public class MyConverter extends Converter<MyDTO, MyEntity> {

    public OrderConverter() {
        super(
            MyConverter::fromDTOToEntity,
            MyConverter::fromEntityToDTO
        );
    }

    private static MyEntity fromDTOToEntity(MyDTO dto) {
        return MyEntity.builder()
            .field1(dto.getField1())
            .field2(dto.getField2())
            .build();
    }

    private static MyDTO fromEntityToDTO(MyEntity entity) {
        return MyDTO.builder()
            .field1(entity.getField1())
            .field2(entity.getField2())
            .build();
    }

}

我想实现这样的目标(这是我需要帮助的地方):

@Configuration
public class ConverterConfiguration {

  @Bean
  public ConverterService converterService() {
    ConverterService converterService = new ConverterService();
    converterService.registerConverter(new MyConverter());
    // Register any other converter...
    return converterService;
  }

}

服务看起来像这样:

public class ConverterService {

  private Map<Key, Converter<?, ?>> converters = new ConcurrentReferenceHashMap<>();

  public void registerConverter(Converter<?, ?> converter) {
    this.converterCache.put(key, converter);
  }

  protected <I, O> I mapBetweenTypes(final O from, final Class<I> clazz) {
    // Based on the parameters I should be able to figure out which function to get from the map and then call (convertFromFirstToSecond or convertFromSecondToFirst)
    // return this.converters.get(key).convertFromFirstToSecond(from);
    return this.converters.get(key).convertFromSecondToFirst(from);
  }

}

【问题讨论】:

    标签: java spring-boot generics design-patterns


    【解决方案1】:

    解决该问题的一种方法是在Converter 类中显式存储属于转换一部分的类型。我会考虑的另一个简化是将转换函数直接存储在地图中,而不是转换器。这样你就不必弄清楚你需要走哪条路。

    第一步,存储类型,并为转换函数添加getter:

    public abstract class Converter<D, E> {
    
      private final Function<D, E> fromFirstToSecond;
      private final Function<E, D> fromSecondToFirst;
      private final Class<D> classOfFirst;
      private final Class<E> classOfSecond;
    
      public Class<D> getClassOfFirst() {
          return classOfFirst;
      }
    
      public Class<E> getClassOfSecond() {
          return classOfSecond;
      }
    
      public Converter(Class<D> first, Class<E> second, 
          Function<D, E> fromFirstToSecond, Function<E, D> fromSecondToFirst) {
        this.fromFirstToSecond = fromFirstToSecond;
        this.fromSecondToFirst = fromSecondToFirst;
        classOfFirst = first;
        classOfSecond = second;
      }
    
      public Function<D, E> getForward() {
          return fromFirstToSecond;
      }
    
      public Function<E, D> getBackward() {
          return fromSecondToFirst;
      }
    

    那么ConverterService可以存储两个方向的转换函数,转换相当于在两级映射中查找。

    public class ConverterService {
    
        private Map<Class<?>, Map<Class<?>, Function<?,?>>> converters = createMap();
    
        public void registerConverter(Converter<?, ?> converter) {
            if( !converters.containsKey(converter.getClassOfFirst())) {
                converters.put(converter.getClassOfFirst(), createInnerMap());
            }
            if( !converters.containsKey(converter.getClassOfSecond())) {
                converters.put(converter.getClassOfSecond(), createInnerMap());
            }
            converters.get(converter.getClassOfFirst()).put(
                converter.getClassOfSecond(), converter.getForward());
            converters.get(converter.getClassOfSecond()).put(
                converter.getClassOfFirst(), converter.getBackward());
        }
    
        @SuppressWarnings("unchecked") // Also needs input validation
        protected <D,E> E mapBetweenTypes(D from, E to) {
            return ((Function<D,E>) converters.get(
                from.getClass()).get(to.getClass())).apply(from);
        }
    
        private static Map<Class<?>, Map<Class<?>, Function<?,?>>> createMap() { 
            return /* Whatever impl you need */ 
        }
    
        private static Map<Class<?>, Function<?,?>> createInnerMap() { 
            return /* Whatever impl you need */ 
        }
    }
    

    【讨论】:

    • 在看到您的回答之前,我最终使用了 spring 通用转换服务。我创建了自己的转换器,然后在 spring 转换服务中注册,剩下的就交给它了。
    猜你喜欢
    • 1970-01-01
    • 2013-06-24
    • 1970-01-01
    • 2010-12-03
    • 1970-01-01
    • 2021-10-11
    • 2020-04-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多