DDD架构下API数据映射至领域实体的正确方式及DataMapper实现咨询
API数据到领域实体的映射方案:不止静态DataMapper
只用包含toDomain、toPersistance、fromApiToDomain静态方法的DataMapper类是可行的,但这只是轻量场景下的选择,具体方案要根据你的业务复杂度和架构约束调整:
一、静态方法DataMapper的适用场景
如果你的映射逻辑简单(比如字段直接对应、基础类型转换),且领域实体没有复杂的构造规则,这种方式足够用:
public class UserMapper { public static User fromApiToDomain(ApiUserDTO dto) { return new User(dto.getUserId(), dto.getUsername(), dto.getEmail()); } public static UserDTO toPersistance(User user) { return new UserDTO(user.getId(), user.getUsername(), user.getEmail()); } }
这种方式的优势是实现简单、无依赖,适合快速开发简单业务。
二、复杂场景下的优化方案
当映射涉及业务规则、依赖外部服务或存在多版本适配时,静态方法的局限性就会显现,这时可以考虑以下方案:
1. 实例化Mapper类(支持依赖注入)
如果映射过程需要依赖领域服务或工厂(比如验证用户邮箱格式是否符合领域规则),静态方法无法注入依赖,此时应该用实例化的Mapper:
public class UserMapper { private final UserFactory userFactory; private final EmailValidationService emailValidationService; public UserMapper(UserFactory userFactory, EmailValidationService emailValidationService) { this.userFactory = userFactory; this.emailValidationService = emailValidationService; } public User fromApiToDomain(ApiUserDTO dto) { emailValidationService.validate(dto.getEmail()); return userFactory.create(dto.getUserId(), dto.getUsername(), dto.getEmail()); } }
这种方式符合依赖倒置原则,Mapper依赖抽象的工厂和服务,而非具体实现。
2. 结合领域工厂创建实体
DDD中,领域实体的创建应该由领域工厂负责,而非Mapper直接实例化。Mapper只需要将API数据转换为工厂所需的参数,由工厂保证实体的业务完整性:
// 领域工厂 public class UserFactory { public static User create(UserId id, Username username, Email email) { if (username.value().isEmpty()) { throw new InvalidUsernameException(); } return new User(id, username, email); } } // Mapper public class UserMapper { public User fromApiToDomain(ApiUserDTO dto) { return UserFactory.create( new UserId(dto.getUserId()), new Username(dto.getUsername()), new Email(dto.getEmail()) ); } }
这里Mapper只做数据格式转换(DTO字段转值对象),实体的业务规则校验由工厂处理,职责更清晰。
3. 策略模式处理多版本映射
如果API存在多版本(比如v1和v2返回不同的用户结构),可以用策略模式定义不同的Mapper实现,通过依赖注入切换:
public interface UserMapper { User fromApiToDomain(Object dto); } public class UserMapperV1 implements UserMapper { @Override public User fromApiToDomain(Object dto) { ApiUserV1DTO v1Dto = (ApiUserV1DTO) dto; // v1映射逻辑 } } public class UserMapperV2 implements UserMapper { @Override public User fromApiToDomain(Object dto) { ApiUserV2DTO v2Dto = (ApiUserV2DTO) dto; // v2映射逻辑 } }
这种方式避免了在单个Mapper里堆砌大量分支判断,扩展性更好。
三、核心原则
- Mapper只负责数据结构转换,不处理业务逻辑;
- 领域实体的完整性由领域层(工厂、实体自身)保证,Mapper不参与业务校验;
- 优先遵循依赖倒置原则,复杂场景下用实例化Mapper替代静态方法。
内容的提问来源于stack exchange,提问作者Igor Bezlepkin
相关产品推荐
相关产品推荐

