Java中转换器设计模式深入讲解

前言

在这篇文章中,我们将讨论 Java / J2EE项目中最常用的  Converter Design Pattern。由于Java8 功能不仅提供了相应类型之间的通用双向转换方式,而且还提供了转换相同类型对象集合的常用方法,从而将样板代码减少到绝对最小值。我们使用Java8 功能编写了此模式的源代码。

目的

转换器设计模式的目的是为相应类型之间的双向转换提供一种通用的方式,允许类型无需彼此了解的简洁的实现。此外,转换器设计模式引入了双向收集映射,将样板代码减少到最小。

源代码

转换器设计模式是一种行为设计模式,允许在相应类型(如DTO和逻辑同构类型的域表示)之间进行双向转换。此外,该模式还引入了一种在类型之间转换对象集合的通用方法。

类图

让我们根据上面的类图编写源代码。

在本例中,我们将把customerd转换为customer实体,反之亦然,我们还将在类型之间转换对象集合。

步骤1:让我们创建一个通用转换器。

public abstract class Converter < T, C > {

 private final Function < T,
 C > fromDto;
 private final Function < C,
 T > fromEntity;

 /**
  * @param fromDto
  *   Function that converts given dto entity into the domain
  *   entity.
  * @param fromEntity
  *   Function that converts given domain entity into the dto
  *   entity.
  */
 public Converter(final Function < T, C > fromDto, final Function < C, T > fromEntity) {
  this.fromDto = fromDto;
  this.fromEntity = fromEntity;
 }

 /**
  * @param customerDto
  *   DTO entity
  * @return The domain representation - the result of the converting function
  *   application on dto entity.
  */
 public final C convertFromDto(final T customerDto) {
  return fromDto.apply(customerDto);
 }

 /**
  * @param customer
  *   domain entity
  * @return The DTO representation - the result of the converting function
  *   application on domain entity.
  */
 public final T convertFromEntity(final C customer) {
  return fromEntity.apply(customer);
 }

 /**
  * @param dtoCustomers
  *   collection of DTO entities
  * @return List of domain representation of provided entities retrieved by
  *   mapping each of them with the conversion function
  */
 public final List < C > createFromDtos(final Collection < T > dtoCustomers) {
  return dtoCustomers.stream().map(this::convertFromDto).collect(Collectors.toList());
 }

 /**
  * @param customers
  *   collection of domain entities
  * @return List of domain representation of provided entities retrieved by
  *   mapping each of them with the conversion function
  */
 public final List < T > createFromEntities(final Collection < C > customers) {
  return customers.stream().map(this::convertFromEntity).collect(Collectors.toList());
 }
}

步骤2:让我们创建一个简单客户转换器的实现。

public class CustomerConverter extends Converter<CustomerDto, Customer> {

 public CustomerConverter() {
 super(customerDto -> new Customer(customerDto.getCustomerId(), customerDto.getCustomerName(),
 customerDto.getCustomerLastName(), customerDto.isStatus()),
 customer -> new CustomerDto(customer.getCustomerId(), customer.getCustomerName(),
  customer.getCustomerLastName(), customer.isStatus()));

 }

}

步骤3: 创建customerdto类。

public class CustomerDto {
 private String customerId;
 private String customerName;
 private String customerLastName;
 private boolean status;
 public CustomerDto(String customerId, String customerName, String customerLastName, boolean status) {
  super();
  this.customerId = customerId;
  this.customerName = customerName;
  this.customerLastName = customerLastName;
  this.status = status;
 }
 public String getCustomerId() {
  return customerId;
 }
 public void setCustomerId(String customerId) {
  this.customerId = customerId;
 }
 public String getCustomerName() {
  return customerName;
 }
 public void setCustomerName(String customerName) {
  this.customerName = customerName;
 }
 public String getCustomerLastName() {
  return customerLastName;
 }
 public void setCustomerLastName(String customerLastName) {
  this.customerLastName = customerLastName;
 }
 public boolean isStatus() {
  return status;
 }
 public void setStatus(boolean status) {
  this.status = status;
 }

}

步骤4: 创建Customer实体类。

public class Customer {
 private String customerId;
 private String customerName;
 private String customerLastName;
 private boolean status;
 public Customer(String customerId, String customerName, String customerLastName, boolean status) {
  super();
  this.customerId = customerId;
  this.customerName = customerName;
  this.customerLastName = customerLastName;
  this.status = status;
 }
 public String getCustomerId() {
  return customerId;
 }
 public void setCustomerId(String customerId) {
  this.customerId = customerId;
 }
 public String getCustomerName() {
  return customerName;
 }
 public void setCustomerName(String customerName) {
  this.customerName = customerName;
 }
 public String getCustomerLastName() {
  return customerLastName;
 }
 public void setCustomerLastName(String customerLastName) {
  this.customerLastName = customerLastName;
 }
 public boolean isStatus() {
  return status;
 }
 public void setStatus(boolean status) {
  this.status = status;
 }
}

步骤5:  现在,让我们通过创建Client类来测试这个模式。

public class Client {
 /**
  * Program entry point
  *
  * @param args command line args
  */
 public static void main(String[] args) {
  Converter < CustomerDto, Customer > CustomerConverter = new CustomerConverter();

  CustomerDto dtoCustomer = new CustomerDto("100", "Ramesh", "Fadatare", true);
  Customer Customer = CustomerConverter.convertFromDto(dtoCustomer);
  System.out.println("Entity converted from DTO:" + Customer);

  List < Customer > customers = new ArrayList < > ();
  customers.add(new Customer("100", "Ramesh1", "Fadatare", true));
  customers.add(new Customer("200", "Ramesh2", "Fadatare", true));
  customers.add(new Customer("300", "Ramesh3", "Fadatare", true));

  customers.forEach(System.out::println);

  customers.forEach((customer) - > System.out.println(customer.getCustomerId()));

  System.out.println("DTO entities converted from domain:");
  List < CustomerDto > dtoEntities = CustomerConverter.createFromEntities(customers);
  dtoEntities.forEach(System.out::println);
  dtoEntities.forEach((customer) - > System.out.println(customer.getCustomerId()));

 }
}

输出:

Entity converted from DTO:com.ramesh.j2ee.converter.Customer@87aac27
com.ramesh.j2ee.converter.Customer@1b28cdfa
com.ramesh.j2ee.converter.Customer@eed1f14
com.ramesh.j2ee.converter.Customer@7229724f
100
200
300
DTO entities converted from domain:
com.ramesh.j2ee.converter.CustomerDto@4dd8dc3
com.ramesh.j2ee.converter.CustomerDto@6d03e736
com.ramesh.j2ee.converter.CustomerDto@568db2f2
100
200
300

适用性

在以下情况下 使用转换器模式:

  • 当您拥有逻辑上与其他类型相对应的类型时,您需要在它们之间转换实体
  • 如果要根据上下文提供不同类型的转换方式
  • 每当您引入DTO(数据传输对象)时,您可能需要将其转换为域等效。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。

(0)

相关推荐

  • Java接口名称冲突问题的讲解

    对于方法重载的区分,主要通过下面三种方式: 1. 参数个数 2. 参数类型 3. 参数顺序(较少使用,维护困难) 至于方法的其他部分,如方法返回值类型.修饰符等,与方法重载则没有任何关系. Java编程时,假设存在两个接口,但接口中存在相同名称的方法,但是其仅返回值不同.如下: interface interfac1{ void method(); } interface interface2 { int method(); } interface interface3 extends inte

  • Java如何将处理完异常之后的程序能够从抛出异常的地点向下执行?

    因为Java中的异常处理理论,支持的是终止模型,在这种模型中,抛出异常之后,程序无法返回到异常发生的地方向下继续执行.但是,如果我们现在想要Java实现类似恢复模型的行为,希望异常在处理之后继续往下进行执行,那么有什么解决的办法吗? 思路: 把try块放在while循环里,这样就能不断的进入try块,直到获得满意的结果结束. 下来看下面的程序: package exceptions; class MyException extends Exception { } public class Con

  • 如何理解Java中基类子对象的构建过程从"基类向外"进行扩散的?

    <Java编程思想>复用类一章,提出基类的子对象的构建过程是从基类"向外"进行扩散的. 下面通过实例进行讲解,首先看下面的代码: import static net.mindview.util.Print.*; //<java编程思想>提供的类库 /** * @author Administrator * */ public class Cat extends Animal { public Cat() { // TODO Auto-generated cons

  • Java为什么匿名内部类参数引用需要用final进行修饰?

    事实上,除了匿名内部类参数,方法和作用域内的内部类内部使用的外部变量也必须是final 的.原因大致总结一下: 简单解释就是: 方法中的局部变量的生命周期很短,方法结束后变量就要被销毁,加上final是为了延长变量的生命周期. 进一步解释: 内部类通常都含有回调,引用那个匿名内部类的函数执行完了就没了,所以内部类中引用外面的局部变量需要是final的,这样在回调的时候才能找到那个变量,而如果是外围类的成员变量就不需要是final的,因为内部类本身都会含有一个外围了的引用(外围类.this),所以

  • Java关于含有继承类的成员初始化过程讲解

    参考资料<Java 编程思想>,关于含有基类的导出类,其成员的初始化过程是一个容易让人困惑的地方,下面通过具体的实例进行讲解,代码取自<Java 编程思想>,代码如下: import static net.mindview.util.Print.*; /** * All rights Reserved, Designed By www.tydic.com * * @project: MyExerciseProject * @Title: Beetle.java * @Package

  • java集合与数组的相同点和不同点

    数组: 数组可以用来保存多个基本数据类型的数据,也可以用来保存多个对象. 数组的长度是不可改变的,一旦初始化数组时就指定了数组的长度(无论是静态初始化还是动态初始化). 数组无法保存具有映射关系的数据. 集合: 集合是只用于存储数量不等的对象. 集合的长度是可变的. 集合可以保存具有映射关系的数据. 相同点: 数组和集合类同是容器. 不同点: 数组的长度是固定的,集合的长度是可变的. 数组只能存储同类型的对象,集合可以存储不同类型的对象. 集合只能存储对象不能存储基本类型 总结 以上就是这篇文章

  • 关于JAVA_HOME路径修改之后JDK的版本依然不更改的解决办法

    今天重新配置Java的时候出现了一点问题,下面主要讲一下自己的解决方案: 问题描述: 今天想更改一下本机JDK的版本,发现更改之后使用 java -version命令,出现的JDK版本并没有变换. 查找原因: 系统目录里面可能有java.exe,导致优先调用了系统目录中的java.exe:刚安装的jdk自动增加了path内容,所增加的内容(指向的路径)下存在java.exe,且在path内容中该路径的顺序位于你自己配置java的路径前面(笔者的坑在这). 解决办法: 将%JAVA_HOME%/b

  • Java中关于子类覆盖父类的抛出异常问题

    Java中子类覆盖父类方法抛出异常不能比父类多,这个表述不够准确. 准确一点的描述为: 子类抛出的异常类型不能比父类抛出的异常类型更宽泛.假设父类抛出异常ParentException,另外有两个子类继承自ParentException分别为ChildException1, ChildException2, 那么 子类可以同时抛出异常ChildException1,ChildException2. 满足"子类抛出的异常类型不能比父类抛出的异常类型更宽泛",这一条件. 注意: 子类也可以

  • Java反射机制的讲解

    Java中的反射提供了一种运行期获取对象元信息的手段.即正常方法是通过一个类创建对象,反射方法就是通过一个对象找到一个类的信息. Java的反射机制的实现要借助于4个类:class,Constructor,Field,Method; 其中class代表的时类对 象,Constructor-类的构造器对象,Field-类的属性对象,Method-类的方法对象.通过这四个对象我们可以粗略的看到一个类的各个组成部分. Java反射的作用: 在Java运行时环境中,对于任意一个类,可以知道这个类有哪些属

  • Java中数组在内存中存放原理的讲解

    Java中数组被实现为对象,它们一般都会因为记录长度而需要额外的内存.对于一个原始数据类型的数组,一般需要24字节的头信息再加上保存值所需的内存,其中24字节的头信息分别包含以下几个部分. 下面分别分析一维.二维.三维的数组存储情况. 下面首先对一维数组进行分析,以int[]型数组为例,假设数组长度为N,那么需要的内存占用(24+4N)个字节,原因分析比较简单,图解示例如下:即占用内存总量=头信息内存+数组N个int值占用内存. 对于二维数组进行分析,首先对于多维数组的概念,大家可以参考这篇文章

随机推荐