文章目录
【Java设计模式】转换器模式:简化跨层数据转换
一、概述
在Java中,转换器模式的目的是提供一种通用、系统的方法,用于在相应的数据类型之间进行双向转换。这允许实现干净、解耦的实现,其中类型彼此不知情。此外,转换器模式支持双向集合映射,最大限度地减少样板代码。
二、转换器设计模式的别名
- Mapper(映射器)
- Translator(翻译器)
三、转换器设计模式的意图
转换器模式的目的是提供一种在相应数据类型之间进行双向转换的通用、系统的方法。这使得实现更加干净、解耦,因为类型之间彼此不了解。此外,该模式支持双向集合映射,减少了样板代码。
四、转换器模式的详细解释及实际示例
- 实际示例:
- 在现实世界的场景中,考虑一个图书馆系统与第三方图书数据库进行交互。图书馆使用内部图书格式,而第三方数据库使用不同的格式。通过使用转换器模式,转换器类可以将第三方图书数据转换为图书馆的格式,反之亦然。这确保了无缝集成,而无需更改任何一个系统的内部结构。
- 通俗解释:
- 转换器模式简化了将一个类的实例映射到另一个类的实例的过程,确保了一致和干净的数据转换。
五、Java中转换器模式的编程示例
在应用程序中,数据库层通常有需要映射到DTO(数据传输对象)以进行业务逻辑处理的实体。这种映射通常涉及许多类,因此需要一个通用的解决方案。
我们引入一个通用的Converter
类:
public class Converter<T, U> {
private final Function<T, U> fromDto;
private final 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 convertFromDto(final T dto) {
return fromDto.apply(dto);
}
public final T convertFromEntity(final U entity) {
return fromEntity.apply(entity);
}
public final List<U> createFromDtos(final Collection<T> dtos) {
return dtos.stream().map(this::convertFromDto).collect(Collectors.toList());
}
public final List<T> createFromEntities(final Collection<U> entities) {
return entities.stream().map(this::convertFromEntity).collect(Collectors.toList());
}
}
专门的转换器从这个基类继承:
public class UserConverter extends Converter<UserDto, User> {
public UserConverter() {
super(UserConverter::convertToEntity, UserConverter::convertToDto);
}
private static UserDto convertToDto(User user) {
return new UserDto(user.firstName(), user.lastName(), user.active(), user.userId());
}
private static User convertToEntity(UserDto dto) {
return new User(dto.firstName(), dto.lastName(), dto.active(), dto.email());
}
}
User
和UserDto
之间的映射变得非常简单:
public static void main(String[] args) {
Converter<UserDto, User> userConverter = new UserConverter();
UserDto dtoUser = new UserDto("John", "Doe", true, "whatever[at]wherever.com");
User user = userConverter.convertFromDto(dtoUser);
LOGGER.info("Entity converted from DTO: {}", user);
var users = List.of(
new User("Camile", "Tough", false, "124sad"),
new User("Marti", "Luther", true, "42309fd"),
new User("Kate", "Smith", true, "if0243")
);
LOGGER.info("Domain entities:");
users.stream().map(User::toString).forEach(LOGGER::info);
LOGGER.info("DTO entities converted from domain:");
List<UserDto> dtoEntities = userConverter.createFromEntities(users);
dtoEntities.stream().map(UserDto::toString).forEach(LOGGER::info);
}
程序输出:
08:28:27.019 [main] INFO com.iluwatar.converter.App -- Entity converted from DTO: User[firstName=John, lastName=Doe, active=true, userId=whatever[at]wherever.com]
08:28:27.035 [main] INFO com.iluwatar.converter.App -- Domain entities:
08:28:27.035 [main] INFO com.iluwatar.converter.App -- User[firstName=Camile, lastName=Tough, active=false, userId=124sad]
08:28:27.035 [main] INFO com.iluwatar.converter.App -- User[firstName=Marti, lastName=Luther, active=true, userId=42309fd]
08:28:27.035 [main] INFO com.iluwatar.converter.App -- User[firstName=Kate, lastName=Smith, active=true, userId=if0243]
08:28:27.036 [main] INFO com.iluwatar.converter.App -- DTO entities converted from domain:
08:28:27.037 [main] INFO com.iluwatar.converter.App -- UserDto[firstName=Camile, lastName=Tough, active=false, email=124sad]
08:28:27.037 [main] INFO com.iluwatar.converter.App -- UserDto[firstName=Marti, lastName=Luther, active=true, email=42309fd]
08:28:27.037 [main] INFO com.iluwatar.converter.App -- UserDto[firstName=Kate, lastName=Smith, active=true, email=if0243]
六、何时在Java中使用转换器模式
在以下情况下使用转换器模式:
- 当存在逻辑上相互对应的类型,并且需要在它们之间进行转换时。
- 在与外部系统或服务交互的应用程序中,这些系统或服务需要特定格式的数据。
- 在集成遗留系统时,其中数据模型与新系统有很大差异。
- 当旨在封装转换逻辑以促进单一职责和更干净的代码时。
七、转换器模式在Java中的实际应用
- 在多层应用程序中进行数据传输对象(DTO)的转换。
- 将第三方数据结构或API响应适配到内部模型。
- ORM(对象 - 关系映射)框架用于在数据库记录和域对象之间进行映射。
- 在微服务架构中用于不同服务之间的数据交换。
八、转换器模式的优点和权衡
优点:
- 分离关注点:将转换逻辑封装在一个单独的组件中,使应用程序的其余部分不了解转换的细节。
- 可重用性:转换器组件可以在应用程序中或甚至在不同的应用程序中重用。
- 灵活性:可以轻松添加新的转换,而不会影响现有代码,符合开闭原则。
- 互操作性:通过转换数据格式,促进不同系统或应用程序层之间的通信。
权衡:
- 开销:引入转换器可能会增加复杂性和潜在的性能开销,特别是在具有众多数据格式的系统中。
- 重复:如果管理不当,存在重复模型定义的风险,导致维护成本增加。
九、源码下载
通过本文的介绍,相信大家对Java中的转换器模式有了更深入的了解。在实际开发中,合理运用该模式可以简化数据转换过程,提高代码的可维护性和灵活性,但需要注意性能开销和模型定义的管理。