轉換器(Converter)模式
阿新 • • 發佈:2019-01-09
在日常編碼中,我們會遇到這樣一個場景:把一個型別的物件轉換成另一個物件,而這兩者之前的轉換強調的是"值(Value)"的等價轉換,兩者之間並沒有繼承與被繼承的關係,也並不是像浮點數轉整數這種語法意義上的轉換關係。如下面舉的這個例子:"使用者"這個物件定義了User和UserDto兩種Bean class來表示,二者所代表的"值"都是一致的,只是一個是業務邏輯層面的,一個是資料訪問層面的。二者之前常常會發生轉換,這個時候可以使用轉換器模式:
類圖:
程式碼:
/** * User class */ public class User { private String firstName; private String lastName; private boolean isActive; private String userId; /** * @param firstName user's first name * @param lastName user's last name * @param isActive flag indicating whether the user is active * @param userId user's identificator */ public User(String firstName, String lastName, boolean isActive, String userId) { this.firstName = firstName; this.lastName = lastName; this.isActive = isActive; this.userId = userId; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public boolean isActive() { return isActive; } public String getUserId() { return userId; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } User user = (User) o; return isActive == user.isActive && Objects.equals(firstName, user.firstName) && Objects .equals(lastName, user.lastName) && Objects.equals(userId, user.userId); } @Override public int hashCode() { return Objects.hash(firstName, lastName, isActive, userId); } @Override public String toString() { return "User{" + "firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + ", isActive=" + isActive + ", userId='" + userId + '\'' + '}'; } }
/** * User DTO class */ public class UserDto { private String firstName; private String lastName; private boolean isActive; private String email; /** * @param firstName user's first name * @param lastName user's last name * @param isActive flag indicating whether the user is active * @param email user's email address */ public UserDto(String firstName, String lastName, boolean isActive, String email) { this.firstName = firstName; this.lastName = lastName; this.isActive = isActive; this.email = email; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public boolean isActive() { return isActive; } public String getEmail() { return email; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } UserDto userDto = (UserDto) o; return isActive == userDto.isActive && Objects.equals(firstName, userDto.firstName) && Objects .equals(lastName, userDto.lastName) && Objects.equals(email, userDto.email); } @Override public int hashCode() { return Objects.hash(firstName, lastName, isActive, email); } @Override public String toString() { return "UserDto{" + "firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + ", isActive=" + isActive + ", email='" + email + '\'' + '}'; } }
/** * Generic converter, thanks to Java8 features not only provides a way of generic bidirectional * conversion between coresponding types, but also a common way of converting a collection of objects * of the same type, reducing boilerplate code to the absolute minimum. * @param <T> DTO representation's type * @param <U> Domain representation's type */ public class Converter<T, U> { private final Function<T, U> fromDto; private final Function<U, 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, U> fromDto, final Function<U, T> fromEntity) { this.fromDto = fromDto; this.fromEntity = fromEntity; } /** * @param userDto DTO entity * @return The domain representation - the result of the converting function application on dto entity. */ public final U convertFromDto(final T userDto) { return fromDto.apply(userDto); } /** * @param user domain entity * @return The DTO representation - the result of the converting function application on domain entity. */ public final T convertFromEntity(final U user) { return fromEntity.apply(user); } /** * @param dtoUsers collection of DTO entities * @return List of domain representation of provided entities retrieved by * mapping each of them with the convertion function */ public final List<U> createFromDtos(final Collection<T> dtoUsers) { return dtoUsers.stream().map(this::convertFromDto).collect(Collectors.toList()); } /** * @param users collection of domain entities * @return List of domain representation of provided entities retrieved by * mapping each of them with the convertion function */ public final List<T> createFromEntities(final Collection<U> users) { return users.stream().map(this::convertFromEntity).collect(Collectors.toList()); } }
/**
* Example implementation of the simple User converter.
*/
public class UserConverter extends Converter<UserDto, User> {
/**
* Constructor.
*/
public UserConverter() {
super(userDto -> new User(userDto.getFirstName(), userDto.getLastName(), userDto.isActive(),
userDto.getEmail()),
user -> new UserDto(user.getFirstName(), user.getLastName(), user.isActive(),
user.getUserId()));
}
}
/**
* The Converter pattern is a behavioral design pattern which allows a common way of bidirectional
* conversion between corresponding types (e.g. DTO and domain representations of the logically
* isomorphic types). Moreover, the pattern introduces a common way of converting a collection of
* objects between types.
*/
public class App {
/**
* Program entry point
*
* @param args command line args
*/
public static void main(String[] args) {
Converter<UserDto, User> userConverter = new Converter<>(
userDto -> new User(userDto.getFirstName(), userDto.getLastName(), userDto.isActive(),
userDto.getEmail()),
user -> new UserDto(user.getFirstName(), user.getLastName(), user.isActive(), user.getUserId()));
UserDto dtoUser = new UserDto("John", "Doe", true, "whatever[at]wherever.com");
User user = userConverter.convertFromDto(dtoUser);
System.out.println("Entity converted from DTO:" + user);
ArrayList<User> users = Lists.newArrayList(new User("Camile", "Tough", false, "124sad"),
new User("Marti", "Luther", true, "42309fd"), new User("Kate", "Smith", true, "if0243"));
System.out.println("Domain entities:");
users.forEach(System.out::println);
System.out.println("DTO entities converted from domain:");
List<UserDto> dtoEntities = userConverter.createFromEntities(users);
dtoEntities.forEach(System.out::println);
}
}