转换器(Converter)设计模式

2024-04-30 13:38

本文主要是介绍转换器(Converter)设计模式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在日常开发的时候,需要在对象之间进行值的 copy,如 POJO,DTO,VO,对象之间有相同的属性,想把一个对象的值 copy 到另一个对象中去,如 从数据库中查询出我们的 POJO 对象的数据,又有个对象是对 POJO 进行包装DTO,现在想把查询出来的 POJO 的值 copy 到 DTO 中相应的属性中去,之后再扩展其属性,对此,一般可以有三种方式进行解决:setter,转换器模式和反射,接下来就看下它们的一个区别:

在区分这三种方式之前,先要定义一下需要进行数据copy的两个类:

Person类:

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Person {private String name;private int age;private String gender;private String job;
}

PersonDto类:

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class PersonDto {private String name;private int age;private String gender;private String address;
}

下面的演示都是用这两个类进行。

setter

通过 setter 方式 copy 数据比较方便,但是如果在很多地方需要进行数据的 copy,就显得有点重复了,当然可以写个工具,专门对该数据进行扩展,如下所示:

       public Person copy(PersonDto personDto) {Person person = new Person();person.setName(personDto.getName());person.setAge(personDto.getAge());person.setGender(personDto.getGender());return person;}

使用该方式比较简单。

转换器(Converter)模式

接下来就到该文章的主题了,可以使用转换器模式来解决该问题,先看下该模式的一个类图:

首先 Converter 类是一个顶层的接口,定义了公共的转换方法,不同类实现该接口来定义自己的转换规则

PersonConverter 类是继承于 Converter 的,定义了从 Person 到 PersonDto 和从 PersonDto 到 Person 的一个转换规则,并向外提供接口以供使用。接下来看下 顶层接口 Converter 类的定义:

/*** 定义转换器* @ Date:Created in 下午 4:44 2018/9/27 0027*/
public class Converter<T, U> {// 从 T 转换为 Uprivate Function<T, U> fromDto;// 从 U 转换为 Tprivate Function<U, T> fromEntity;public Converter(final Function<T, U> fromDto, final Function<U, T> fromEntity) {this.fromDto = fromDto;this.fromEntity = fromEntity;}public final U converterFromDto(final T dto){return fromDto.apply(dto);}public final T converterFromEntity(final U entity){return fromEntity.apply(entity);}public final List<U> batchConverterFromDto(final List<T> dtos){return dtos.stream().map(this::converterFromDto).collect(Collectors.toList());}public final List<T> batchConverterFromEntity(final List<U> entities){return entities.stream().map(this::converterFromEntity).collect(Collectors.toList());}
}

然后在看看 Person 类的自定义转换规则,PersonConverter类:

/*** Person 转换器* @ Date:Created in 下午 5:00 2018/9/27 0027*/
public class PersonConverter extends Converter<PersonDto, Person> {public PersonConverter() {super(new PersonDtoFunction(), new PersonFunction());}// 自定义转换规则static class PersonDtoFunction implements Function<PersonDto, Person> {@Overridepublic Person apply(PersonDto personDto) {// 可定制需要复制的属性Person person = new Person();person.setName(personDto.getName());person.setAge(personDto.getAge());person.setGender(personDto.getGender());return person;}}// 自定义转换规则static class PersonFunction implements Function<Person, PersonDto> {@Overridepublic PersonDto apply(Person person) {// 可定制需要复制的属性PersonDto dto = new PersonDto();dto.setName(person.getName());dto.setAge(person.getAge());dto.setGender(person.getGender());return dto;}}
}

接下来进行测试一番:

PersonDto 转换为 Person:

        Converter<PersonDto, Person> converter = new PersonConverter();PersonDto personDto = new PersonDto("zhangsan", 23, "male", "chengdou");Person person =  converter.converterFromDto(personDto);System.out.println(person); // Person(name=zhangsan, age=23, gender=male, job=null)

批量 PersonDto 转换为 Person:

        PersonDto pd1 = new PersonDto("AAA", 20, "male", "beijing");PersonDto pd2 = new PersonDto("BBB", 21, "female", "shanghai");PersonDto pd3 = new PersonDto("CCC", 22, "male", "chengdou");List<PersonDto> dtos = Lists.newArrayList(pd1, pd2, pd3);List<Person> persons = converter.batchConverterFromDto(dtos);persons.forEach((x) -> System.out.println(x));结果:
Person(name=AAA, age=20, gender=male, job=null)
Person(name=BBB, age=21, gender=female, job=null)
Person(name=CCC, age=22, gender=male, job=null)

从 Perosn 转换为  PersonDto:

        Person person1 = new Person("lisi", 25, "female", "java");PersonDto personDto1 = converter.converterFromEntity(person1);System.out.println(personDto1);// PersonDto(name=lisi, age=25, gender=female, address=null)

批量 从 Perosn 转换为  PersonDto:

        Person p1 = new Person("DDD", 25, "male", "java");Person p2 = new Person("EEE", 26, "male", "python");Person p3 = new Person("FFF", 27, "female", "C++");List<Person> persons1 = Lists.newArrayList(p1, p2, p3);List<PersonDto> dtos1 = converter.batchConverterFromEntity(persons1);dtos1.forEach((x) -> System.out.println(x));结果:PersonDto(name=DDD, age=25, gender=male, address=null)
PersonDto(name=EEE, age=26, gender=male, address=null)
PersonDto(name=FFF, age=27, gender=female, address=null)

以上就是转换器模式的内容了,还是很好扩展的,不过,每个类需要自己定义一个转换规则,这个和写一个该类的转换工具方法有什么区别哦??

反射

第三种 copy 数据的方法就是反射了,使用反射后,可以复制所有的类的数据,不用每个类专门写工具方法和转换器了,如下所示:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;/**** @ Date:Created in 上午 9:27 2018/9/28 0028*/
public final class BeanDataConverter {public static void converterData(Object fromBean, Object toBean, String[] excludeProperties)throws InvocationTargetException, IllegalAccessException {Objects.requireNonNull(fromBean);Objects.requireNonNull(toBean);Objects.requireNonNull(excludeProperties);List<String> excludes = Arrays.stream(excludeProperties).map(String::toLowerCase).collect(Collectors.toList());Method[] methods = fromBean.getClass().getMethods();for (Method method : methods) {String methodName = method.getName();if (!methodName.startsWith("get") || "getClass".equals(methodName)|| excludes.contains(methodName.replaceFirst("get", "").toLowerCase())){continue;}Class<?> returnType = method.getReturnType();Object value = method.invoke(fromBean, new Object[]{ });String setMethodName = String.format("set%s", methodName.replaceFirst("get", ""));try {Method setMethod = toBean.getClass().getMethod(setMethodName, returnType);setMethod.invoke(toBean, value);} catch (NoSuchMethodException e) { }}}
}

测试一波:

        PersonDto personDto = new PersonDto("zhangsan", 23, "male", "chengdou");Person p4 = new Person();// 不排除属性,复制全部属性String[] excludes = {};BeanDataConverter.converterData(personDto, p4, excludes);System.out.println(p4);// Person(name=zhangsan, age=23, gender=male, job=null)Person p5 = new Person();// 排除 name 属性,即不复制 name 属性的值:String[] excludes2 = {"name"};BeanDataConverter.converterData(personDto, p5, excludes2);System.out.println(p5);//  Person(name=null, age=23, gender=male, job=null)

以上就是使用 反射来进行copy数据了,可以看到反射是很强大的,适用于所有的数据copy,个人感觉比 转换模式要好些呢。

这篇关于转换器(Converter)设计模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/949014

相关文章

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

设计模式之工厂模式(通俗易懂--代码辅助理解【Java版】)

文章目录 1、工厂模式概述1)特点:2)主要角色:3)工作流程:4)优点5)缺点6)适用场景 2、简单工厂模式(静态工厂模式)1) 在简单工厂模式中,有三个主要角色:2) 简单工厂模式的优点包括:3) 简单工厂模式也有一些限制和考虑因素:4) 简单工厂模式适用场景:5) 简单工厂UML类图:6) 代码示例: 3、工厂方法模式1) 在工厂方法模式中,有4个主要角色:2) 工厂方法模式的工作流程

C#设计模式(1)——单例模式(讲解非常清楚)

一、引言 最近在学设计模式的一些内容,主要的参考书籍是《Head First 设计模式》,同时在学习过程中也查看了很多博客园中关于设计模式的一些文章的,在这里记录下我的一些学习笔记,一是为了帮助我更深入地理解设计模式,二同时可以给一些初学设计模式的朋友一些参考。首先我介绍的是设计模式中比较简单的一个模式——单例模式(因为这里只牵涉到一个类) 二、单例模式的介绍 说到单例模式,大家第一

漫谈设计模式 [12]:模板方法模式

引导性开场 菜鸟:老大,我最近在做一个项目,遇到了点麻烦。我们有很多相似的操作流程,但每个流程的细节又有些不同。我写了很多重复的代码,感觉很乱。你有啥好办法吗? 老鸟:嗯,听起来你遇到了典型的代码复用和维护问题。你有没有听说过“模板方法模式”? 菜鸟:模板方法模式?没听过。这是什么? 老鸟:简单来说,模板方法模式让你在一个方法中定义一个算法的骨架,而将一些步骤的实现延迟到子类中。这样,你可

漫谈设计模式 [9]:外观模式

引导性开场 菜鸟:老鸟,我最近在做一个项目,感觉代码越来越复杂,我都快看不懂了。尤其是有好几个子系统,它们之间的调用关系让我头疼。 老鸟:复杂的代码确实让人头疼。你有没有考虑过使用设计模式来简化你的代码结构? 菜鸟:设计模式?我听说过一些,但不太了解。你觉得我应该用哪个模式呢? 老鸟:听起来你的问题可能适合用**外观模式(Facade Pattern)**来解决。我们可以一起探讨一下。

css选择器和xpath选择器在线转换器

具体前往:Css Selector(选择器)转Xpath在线工具

设计模式大全和详解,含Python代码例子

若有不理解,可以问一下这几个免费的AI网站 https://ai-to.cn/chathttp://m6z.cn/6arKdNhttp://m6z.cn/6b1quhhttp://m6z.cn/6wVAQGhttp://m6z.cn/63vlPw 下面是设计模式的简要介绍和 Python 代码示例,涵盖主要的创建型、结构型和行为型模式。 一、创建型模式 1. 单例模式 (Singleton

漫谈设计模式 [6]:适配器模式

引导性开场 菜鸟:老鸟,我最近在项目中遇到一个问题,我们的系统需要集成一个新的第三方库,但这个库的接口和我们现有的代码完全不兼容。我该怎么办? 老鸟:这是个常见的问题,很多开发者都会遇到这种情况。你有没有听说过适配器模式? 菜鸟:适配器模式?没有,能详细说说吗? 老鸟:当然可以!这就是我们今天要讨论的主题。适配器模式是一个设计模式,可以帮助我们解决你现在遇到的问题。 渐进式介绍概念 老

2 观察者模式(设计模式笔记)

2 观察者模式(别名:发布-订阅) 概念 定义对象间的一种一对多的依赖关系,当一个对象状态发生变化时,所以依赖于它的对象都得到通知并被自动更新。 模式的结构与使用 角色 主题(Subject)观察者(Observer)具体主题(ConcreteSubject)具体观察者(ConcreteObserver) 结构 Subject依赖于Observer最重要!!! package

1 单例模式(设计模式笔记)

1 单例模式 概述:使得一个类的对象成为系统中的唯一实例。 具体实现: 构造函数私有化 限制实例的个数 懒汉式(时间换空间) public class Singleton2 {public static Singleton2 singleton2;private Singleton2(){}public static Singleton2 getInstance() throws I