ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Converter 模式在 Java 中的实践:java-design-patterns 仓库 DTO 与领域实体双向转换源码解析

Converter 模式在 Java 中的实践:java-design-patterns 仓库 DTO 与领域实体双向转换源码解析 示例工程教程【免费下载链接】java-design-patternsDesign patterns implemented in Java项目地址https://gitcode.com/GitHub_Trending/ja/java-design-patterns点击查看免费下载Converter转换器模式是 Java 分层应用中高频使用的数据映射方案它通过一个泛型基类封装 DTO 与领域实体之间的双向转换逻辑让参与转换的类型彼此完全解耦并将集合级批量映射的样板代码压缩到极致。本文以 java-design-patterns 仓库 converter 模块西班牙语翻译版见 localization/es/converter/README.md为骨架结合真实源码与测试用例完整讲解该模式的意图、泛型设计、特化实现、运行效果与适用边界读完即可在自己的多层应用中落地一套干净、可复用、可测试的转换层。模式定位为什么需要 Converter在典型的分层架构中数据库层以实体Entity形式暴露数据而业务逻辑层通常更愿意消费 DTOData Transfer Object数据传输对象。这两类类型在逻辑上一一对应却因为职责不同而拥有不同的字段形态——例如实体持有userId作为内部主键DTO 则携带email用于对外传输源码 User.java 与 UserDto.java 正是如此。当系统中存在大量需要互相映射的类时如果为每一对类型手写映射代码会产生海量重复样板代码。Converter 模式的目标正是提供一种通用、系统化、双向的转换机制双向转换既能从 DTO 转换出领域实体也能从领域实体转换回 DTO类型解耦转换双方互不了解只依赖注入的转换函数集合批量映射一次调用完成整个集合的双向转换样板代码降到最低。该模式在仓库 front matter 中被归入Creational创建型分类并标注了Decoupling解耦标签在英文版 README.md 中它还被称为Mapper映射器或Translator翻译器。现实场景从一个经典例子理解动机原文档给出了一个直观的现实场景数据库层的实体需要被映射为 DTO 供业务逻辑层使用而这类映射需要覆盖数量可能极其庞大的类。如果逐个手写代码会迅速失控我们真正需要的是一种通用的、一次定义处处复用的映射方式。用一句话概括Converter 模式让把一个类的实例映射为另一个类的实例这件事变得简单、一致且可复用。它也常被用于对接第三方系统或遗留系统——当外部数据格式与内部模型不一致时一个转换器就能在不改动任何一方内部结构的前提下完成格式翻译。源码级剖析泛型基类 ConverterT, U仓库中的核心实现位于 Converter.java它借助 Java 8 的函数式接口把整个模式压缩成一个极小却完备的泛型类RequiredArgsConstructor public class ConverterT, U { private final FunctionT, U fromDto; private final FunctionU, T 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 ListU createFromDtos(final CollectionT dtos) { return dtos.stream().map(this::convertFromDto).toList(); } public final ListT createFromEntities(final CollectionU entities) { return entities.stream().map(this::fromEntity::apply).toList(); } }对照源码逐点说明设计细节泛型参数约定源码 Javadoc 明确给出param T DTO representations typeDTO 表示类型、param U Domain representations type领域表示类型。也就是说ConverterUserDto, User表示DTO 为UserDto、领域实体为User的转换器方向语义清晰。依赖注入而非继承复用两个私有的Function字段——fromDtoDTO→领域与fromEntity领域→DTO——通过构造器注入配合 Lombok 的RequiredArgsConstructor自动生成构造函数。这使得每个转换器实例都携带自己的转换策略符合组合优于继承的思想。四个公开方法的职责convertFromDto/convertFromEntity单对象双向转换内部就是对注入函数的apply调用方法被声明为final防止子类覆写破坏统一语义createFromDtos/createFromEntities集合级批量转换用 Stream 对每个元素执行对应转换。注意当前源码使用Stream.toList()Java 16比文档示例中的collect(Collectors.toList())更简洁二者语义等价。一个类解决 N 个映射所有特化转换器共享这套模板新映射只需提供两个函数无需重写循环或集合逻辑。领域模型与 DTO一对结构对应、职责分离的 record参与示例的两个类型在仓库中均为 Javarecord这正是当前仓库的实装风格public record User(String firstName, String lastName, boolean active, String userId) {}public record UserDto(String firstName, String lastName, boolean active, String email) {}两者字段几乎一一对应但存在一处刻意的不对称User以userId标识内部用户UserDto则用email承载对外信息。这个差异恰恰说明了为什么不能简单复用同一个对象——实体面向持久化与业务DTO 面向传输与接口契约Converter 正是二者之间的翻译层。说明西班牙语文档示例代码中使用的是getFirstName()、isActive()等 getter 风格而当前仓库源码已演进为 record 的访问器风格firstName()、active()本文以仓库实际源码为准。特化转换器UserConverter 的极简实现有了泛型基类特化转换器变得异常轻量。源码 UserConverter.java 只做一件事提供两个方向的转换函数并交给父类public class UserConverter extends ConverterUserDto, 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()); } }要点方法引用传参构造器通过UserConverter::convertToEntity和UserConverter::convertToDto两个静态方法引用填充Converter的fromDto与fromEntity字段函数式编程让配置转换策略变成一行代码映射细节集中在私有方法convertToDto把实体的userId映射到 DTO 的email位置示例演示场景下二者承载同一数据convertToEntity反向操作字段如何对应、是否需要格式化或校验全部收拢在这两个方法里业务层无感知。实际运行App 入口完整演示仓库提供了可直接运行的程序入口 App.java完整展示了单对象转换与集合批量转换两种用法public static void main(String[] args) { ConverterUserDto, 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:); ListUserDto dtoEntities userConverter.createFromEntities(users); dtoEntities.stream().map(UserDto::toString).forEach(LOGGER::info); }对应的典型运行输出如下Entity converted from DTO: User[firstNameJohn, lastNameDoe, activetrue, userIdwhatever[at]wherever.com] Domain entities: User[firstNameCamile, lastNameTough, activefalse, userId124sad] User[firstNameMarti, lastNameLuther, activetrue, userId42309fd] User[firstNameKate, lastNameSmith, activetrue, userIdif0243] DTO entities converted from domain: UserDto[firstNameCamile, lastNameTough, activefalse, email124sad] UserDto[firstNameMarti, lastNameLuther, activetrue, email42309fd] UserDto[firstNameKate, lastNameSmith, activetrue, emailif0243]可以看到createFromEntities(users)一次调用就把整个ListUser批量翻译为ListUserDto业务代码零循环、零样板。你可以在 converter/pom.xml 所在模块下通过 Maven仓库根目录提供 mvnw 包装器运行该模块的App观察效果。两种视图类图与序列图原文档附有类图英文版另附序列图二者分别从静态结构与动态流程两个角度佐证上述实现。类图展示了ConverterT,U泛型基类如何通过fromDto、fromEntity两个函数式属性封装双向转换能力UserConverter如何继承基类并针对User与UserDto提供具体实现以及User/UserDto这对结构对应、职责分离的领域与传输类型。序列图则以图书系统对接第三方图书数据库为例动态展示双向转换调用链ExternalBookAPI的第三方数据经BookConverter转为LibraryBook供LibrarySystem使用用户更新后的LibraryBook再反向转回ThirdPartyBook回写外部系统——这正是 DTO/领域实体双向映射在真实业务中的落地场景。测试验证双向映射的一致性保证模式是否可靠仓库给出了直接证据。测试文件 ConverterTest.java 用四组用例覆盖了模式的关键性质双向往返一致双射testConversionsStartingFromDomain先convertFromEntity再convertFromDto断言结果与原始User相等testConversionsStartingFromDto反向执行同样的往返并断言相等。这验证了转换函数互为逆映射的核心前提——只要两个方向函数配对正确数据可在 DTO 与实体间无损往返。自定义转换策略testCustomConverter用 lambda 即时构建一个全新ConverterUserDto, User演示了通过注入不同函数即可实现完全不同的映射规则例如按姓氏拼接生成 email无需新增任何类。集合级往返testCollectionConversion对三个用户的集合执行createFromEntities再createFromDtos断言往返后与原始集合相等验证了批量映射同样保持一致性。此外 AppTest.java 对程序入口做了冒烟测试保证示例可运行。适用场景何时使用 Converter 模式原文档明确给出三条适用判据结合源码可以进一步展开存在逻辑上互相对应的类型且需要在它们之间频繁转换——例如实体与 DTO、外部 API 模型与内部领域模型需要根据上下文提供不同的转换方式——源码中Converter通过注入Function定义策略同一对类型完全可以注册多套转换规则testCustomConverter即证只要引入了 DTO就很可能需要一个等价物把它转换回领域模型——否则业务层会被 DTO 语义污染或被迫手写散落的映射代码。从英文版 README 的归纳看该模式还特别适合对接要求特定数据格式的外部系统与服务、遗留系统与新系统数据模型差异较大的集成场景以及希望把转换逻辑封装为单一职责组件以保持代码整洁的场合。收益与权衡收益关注点分离转换逻辑收敛在独立组件中其余应用代码完全不感知映射细节可复用性一个转换器可被应用内甚至跨应用反复使用灵活性新增转换不触碰既有代码天然贴合开闭原则Open/Closed Principle互操作性统一了不同系统、不同分层之间的数据格式翻译。权衡引入额外开销在数据格式繁多的系统中转换器数量会增加复杂度也可能带来轻微的性能开销模型重复风险DTO 与实体并存本身就是双份模型定义若不加管理会造成维护成本上升——建议保持映射关系集中、字段命名一致并用测试锁定双向一致性。与相邻模式的边界Adapter适配器两者都解决接口不匹配问题但 Adapter 聚焦接口适配Converter 聚焦数据模型翻译Facade外观Facade 为复杂系统提供简化门面其中可能涉及数据转换Strategy策略Converter 通过注入不同Function即可切换转换策略与 Strategy 的思想同源testCustomConverter是最直接的例证。仓库导读如果你想进一步深入核心实现见 Converter.java特化示例见 UserConverter.java运行入口见 App.java测试用例见 ConverterTest.java模式定义与适用说明见英文版 converter/README.md 与本文依据的西班牙语版 localization/es/converter/README.md。对照阅读源码、测试与文档你将完整掌握这一在 Java 分层应用中极具实用价值的数据映射模式。赞分享示例工程教程【免费下载链接】java-design-patternsDesign patterns implemented in Java项目地址https://gitcode.com/GitHub_Trending/ja/java-design-patterns点击查看免费下载相关推荐Java 设计模式之 Converter 模式以 java-design-patterns 为例详解 DTO 与领域对象的双向转换Java 设计模式之 Converter 模式以 java design patterns 为例详解 DTO 与领域对象的双向转换 Converter转换器示例工程教程Java 设计模式之 Converter转换器模式在 java-design-patterns 中实现跨层数据双向转换Java 设计模式之 Converter转换器模式在 java design patterns 中实现跨层数据双向转换 Converter转换器又名示例工程教程Java 领域模型模式Domain Model Pattern实战指南以 java-design-patterns 仓库为例Java 领域模型模式Domain Model Pattern实战指南以 java design patterns 仓库为例 领域模型模式Domain示例工程教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表