基于Movie/BaseDTO继承结构,如何实现含子类字段的父类对象返回与实体转DTO?
解决方案:子类字段兼容的父类返回与实体转DTO实现
嘿,我来帮你搞定这两个需求!先把咱们的基础DTO类结构梳理清楚(完全贴合你描述的继承和Builder设计),再一步步实现功能。
第一步:先定义完整的DTO类结构
首先按照你的要求实现BaseDTO、Movie和UserMovie类,包括泛型Builder的继承:
// 基础DTO抽象类,包含通用字段和Builder基类 abstract class BaseDTO { protected final Long id; protected BaseDTO(BaseDTO.Builder<?> builder) { this.id = builder.id; } // 泛型Builder基类,确保链式调用的类型正确性 abstract static class Builder<T extends Builder<T>> { protected Long id; public T id(Long id) { this.id = id; return self(); } // 子类Builder必须实现此方法返回自身,保证链式调用 protected abstract T self(); public abstract BaseDTO build(); } } // Movie类,继承BaseDTO并实现自己的Builder class Movie extends BaseDTO { protected final String title; protected final Integer releaseYear; protected Movie(Movie.Builder<?> builder) { super(builder); this.title = builder.title; this.releaseYear = builder.releaseYear; } // Movie的泛型Builder,继承自BaseDTO.Builder static class Builder<T extends Builder<T>> extends BaseDTO.Builder<T> { protected String title; protected Integer releaseYear; public T title(String title) { this.title = title; return self(); } public T releaseYear(Integer releaseYear) { this.releaseYear = releaseYear; return self(); } @Override protected T self() { return (T) this; } @Override public Movie build() { return new Movie(this); } } // 快速创建Builder的静态方法 public static Movie.Builder<?> builder() { return new Movie.Builder<>(); } } // UserMovie类,继承Movie并新增专属字段,Builder继承Movie.Builder class UserMovie extends Movie { private final Integer yourRating; private final boolean favorited; protected UserMovie(UserMovie.Builder builder) { super(builder); this.yourRating = builder.yourRating; this.favorited = builder.favorited; } // UserMovie的Builder,指定泛型为自身,确保链式调用流畅 static class Builder extends Movie.Builder<UserMovie.Builder> { private Integer yourRating; private boolean favorited; public UserMovie.Builder yourRating(Integer yourRating) { this.yourRating = yourRating; return self(); } public UserMovie.Builder favorited(boolean favorited) { this.favorited = favorited; return self(); } @Override protected UserMovie.Builder self() { return this; } @Override public UserMovie build() { return new UserMovie(this); } } // 快速创建Builder的静态方法 public static UserMovie.Builder builder() { return new UserMovie.Builder(); } // 子类字段的Getter方法(私有终态字段需要暴露访问) public Integer getYourRating() { return yourRating; } public boolean isFavorited() { return favorited; } }
需求一:返回包含子类字段的父类对象的方法
这里的核心逻辑是:父类类型的引用可以指向子类实例,所以我们可以写一个返回Movie类型的方法,但实际返回UserMovie的实例,这样这个Movie对象就天然包含子类的专属字段。
实现示例
/** * 返回包含用户专属字段的Movie对象(实际是UserMovie实例) */ public Movie getMovieWithUserSpecificFields(Long movieId, Integer userRating, boolean isFavorited) { // 这里可以替换为从数据库/接口获取真实数据的逻辑 return UserMovie.builder() .id(movieId) .title("星际穿越") .releaseYear(2014) .yourRating(userRating) .favorited(isFavorited) .build(); }
如何访问子类字段
当你拿到这个Movie对象后,可以通过类型判断+向下转型来获取子类的专属字段:
// 调用方法获取Movie对象 Movie movie = getMovieWithUserSpecificFields(1001L, 5, true); // 判断是否为UserMovie实例后转型访问字段 if (movie instanceof UserMovie) { UserMovie userMovie = (UserMovie) movie; System.out.println("你的评分:" + userMovie.getYourRating()); System.out.println("是否收藏:" + userMovie.isFavorited()); }
需求二:实体到DTO对象的转换
假设我们有对应的数据库实体类(MovieEntity和UserMovieEntity),我们可以利用DTO的Builder来实现简洁的转换逻辑。
先定义实体类示例
// 电影实体类 class MovieEntity { private Long id; private String title; private Integer releaseYear; // Getter & Setter public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public Integer getReleaseYear() { return releaseYear; } public void setReleaseYear(Integer releaseYear) { this.releaseYear = releaseYear; } } // 用户电影关联实体类 class UserMovieEntity { private Long id; private String title; private Integer releaseYear; private Integer yourRating; private boolean favorited; // Getter & Setter public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public Integer getReleaseYear() { return releaseYear; } public void setReleaseYear(Integer releaseYear) { this.releaseYear = releaseYear; } public Integer getYourRating() { return yourRating; } public void setYourRating(Integer yourRating) { this.yourRating = yourRating; } public boolean isFavorited() { return favorited; } public void setFavorited(boolean favorited) { this.favorited = favorited; } }
实现转换方法
可以写一个静态工具类,或者直接在DTO类中添加静态转换方法,这里用静态工具类示例:
class DTOConverter { // Movie实体转Movie DTO public static Movie convertToMovieDTO(MovieEntity entity) { return Movie.builder() .id(entity.getId()) .title(entity.getTitle()) .releaseYear(entity.getReleaseYear()) .build(); } // UserMovie实体转UserMovie DTO public static UserMovie convertToUserMovieDTO(UserMovieEntity entity) { return UserMovie.builder() .id(entity.getId()) .title(entity.getTitle()) .releaseYear(entity.getReleaseYear()) .yourRating(entity.getYourRating()) .favorited(entity.isFavorited()) .build(); } // 需求一结合:返回包含子类字段的父类DTO public static Movie convertToMovieWithUserFields(UserMovieEntity entity) { return convertToUserMovieDTO(entity); // 直接向上转型为Movie } }
使用示例
// 模拟从数据库获取实体 UserMovieEntity userMovieEntity = new UserMovieEntity(); userMovieEntity.setId(1002L); userMovieEntity.setTitle("盗梦空间"); userMovieEntity.setReleaseYear(2010); userMovieEntity.setYourRating(5); userMovieEntity.setFavorited(true); // 转换为包含子类字段的Movie对象 Movie movie = DTOConverter.convertToMovieWithUserFields(userMovieEntity); // 访问子类字段 if (movie instanceof UserMovie) { UserMovie userMovie = (UserMovie) movie; System.out.println("电影名称:" + userMovie.title); // Movie的字段 System.out.println("你的评分:" + userMovie.getYourRating()); // UserMovie的字段 }
内容的提问来源于stack exchange,提问作者JONKI
相关产品推荐
相关产品推荐

